From 382fb8c68c8c6caa18064cb53a871fff1168906c Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Thu, 4 Dec 2025 07:37:27 -0800 Subject: [PATCH 01/40] [http-specs] Add http-specs tests for CSV encoding on model properties (#9106) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds scenario tests for array encoding on model properties, covering all four `ArrayEncoding` variants. ## Changes - **New test folder**: `packages/http-specs/specs/encode/array/` - **Scenarios added**: - `commaDelimited` (CSV) - values joined with `,` - `spaceDelimited` (SSV) - values joined with ` ` - `pipeDelimited` - values joined with `|` - `newlineDelimited` - values joined with `\n` ## Example ```tsp model CommaDelimitedArrayProperty { @encode(ArrayEncoding.commaDelimited) value: string[]; } @route("/property/comma-delimited") @post op commaDelimited(@body body: CommaDelimitedArrayProperty): CommaDelimitedArrayProperty; ``` Expected request/response body: ```json { "value": "blue,red,green" } ``` > [!WARNING] > >
> Firewall rules blocked me from connecting to one or more addresses (expand for details) > > #### I tried to connect to the following addresses, but was blocked by firewall rules: > > - `telemetry.astro.build` > - Triggering command: `/usr/local/bin/node node /home/REDACTED/work/typespec/typespec/website/node_modules/.bin/../astro/astro.js build` (dns block) > > If you need me to access, download, or install something from one of these locations, you can either: > > - Configure [Actions setup steps](https://gh.io/copilot/actions-setup-steps) to set up my environment, which run before the firewall is enabled > - Add the appropriate URLs or hosts to the custom allowlist in this repository's [Copilot coding agent settings](https://github.com/microsoft/typespec/settings/copilot/coding_agent) (admins only) > >
Original prompt > > ---- > > *This section details on the original issue you should resolve* > > CSV encoding for model properties Scenario tests > Add http-specs tests for array encoding, including all four encode. Add a new folder under packages/http-specs/specs/encode. > > ## Comments on the Issue (you are @copilot in this section) > > > >
- Fixes microsoft/typespec#9029 --- 💬 We'd love your input! Share your thoughts on Copilot coding agent in our [2 minute survey](https://gh.io/copilot-coding-agent-survey). --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: tadelesh <1726438+tadelesh@users.noreply.github.com> Co-authored-by: tadelesh --- ...-csv-encoding-tests-2025-10-28-11-48-49.md | 7 ++ packages/http-specs/spec-summary.md | 84 +++++++++++++ .../http-specs/specs/encode/array/main.tsp | 112 ++++++++++++++++++ .../http-specs/specs/encode/array/mockapi.ts | 43 +++++++ 4 files changed, 246 insertions(+) create mode 100644 .chronus/changes/copilot-add-csv-encoding-tests-2025-10-28-11-48-49.md create mode 100644 packages/http-specs/specs/encode/array/main.tsp create mode 100644 packages/http-specs/specs/encode/array/mockapi.ts diff --git a/.chronus/changes/copilot-add-csv-encoding-tests-2025-10-28-11-48-49.md b/.chronus/changes/copilot-add-csv-encoding-tests-2025-10-28-11-48-49.md new file mode 100644 index 00000000000..d2a1d3706c7 --- /dev/null +++ b/.chronus/changes/copilot-add-csv-encoding-tests-2025-10-28-11-48-49.md @@ -0,0 +1,7 @@ +--- +changeKind: feature +packages: + - "@typespec/http-specs" +--- + +Add tests for array encode. \ No newline at end of file diff --git a/packages/http-specs/spec-summary.md b/packages/http-specs/spec-summary.md index 082812f7ef7..70862966e7d 100644 --- a/packages/http-specs/spec-summary.md +++ b/packages/http-specs/spec-summary.md @@ -105,6 +105,90 @@ Expected behavior: Should handle nested and combined formatting. Test italic text formatting using _single asterisks_. Expected behavior: Text between \* should render as italic. +### Encode_Array_Property_commaDelimited + +- Endpoint: `post /encode/array/property/comma-delimited` + +Test operation with request and response model contains a string array property with commaDelimited encode. +Expected request body: + +```json +{ + "value": "blue,red,green" +} +``` + +Expected response body: + +```json +{ + "value": "blue,red,green" +} +``` + +### Encode_Array_Property_newlineDelimited + +- Endpoint: `post /encode/array/property/newline-delimited` + +Test operation with request and response model contains a string array property with newlineDelimited encode. +Expected request body: + +```json +{ + "value": "blue\nred\ngreen" +} +``` + +Expected response body: + +```json +{ + "value": "blue\nred\ngreen" +} +``` + +### Encode_Array_Property_pipeDelimited + +- Endpoint: `post /encode/array/property/pipe-delimited` + +Test operation with request and response model contains a string array property with pipeDelimited encode. +Expected request body: + +```json +{ + "value": "blue|red|green" +} +``` + +Expected response body: + +```json +{ + "value": "blue|red|green" +} +``` + +### Encode_Array_Property_spaceDelimited + +- Endpoint: `post /encode/array/property/space-delimited` + +Test operation with request and response model contains a string array property with spaceDelimited encode. +Expected request body: + +```json +{ + "value": "blue red green" +} +``` + +Expected response body: + +```json +{ + "value": "blue red green" +} +``` + ### Encode_Bytes_Header_base64 - Endpoint: `get /encode/bytes/header/base64` diff --git a/packages/http-specs/specs/encode/array/main.tsp b/packages/http-specs/specs/encode/array/main.tsp new file mode 100644 index 00000000000..4e707eeb41d --- /dev/null +++ b/packages/http-specs/specs/encode/array/main.tsp @@ -0,0 +1,112 @@ +import "@typespec/http"; +import "@typespec/spector"; + +using Http; +using Spector; + +@doc("Test for encode decorator on array.") +@scenarioService("/encode/array") +namespace Encode.Array; + +model CommaDelimitedArrayProperty { + @encode(ArrayEncoding.commaDelimited) + value: string[]; +} + +model SpaceDelimitedArrayProperty { + @encode(ArrayEncoding.spaceDelimited) + value: string[]; +} + +model PipeDelimitedArrayProperty { + @encode(ArrayEncoding.pipeDelimited) + value: string[]; +} + +model NewlineDelimitedArrayProperty { + @encode(ArrayEncoding.newlineDelimited) + value: string[]; +} + +@route("/property") +namespace Property { + @route("/comma-delimited") + @scenario + @scenarioDoc(""" + Test operation with request and response model contains a string array property with commaDelimited encode. + Expected request body: + ```json + { + "value": "blue,red,green" + } + ``` + Expected response body: + ```json + { + "value": "blue,red,green" + } + ``` + """) + @post + op commaDelimited(@body body: CommaDelimitedArrayProperty): CommaDelimitedArrayProperty; + + @route("/space-delimited") + @scenario + @scenarioDoc(""" + Test operation with request and response model contains a string array property with spaceDelimited encode. + Expected request body: + ```json + { + "value": "blue red green" + } + ``` + Expected response body: + ```json + { + "value": "blue red green" + } + ``` + """) + @post + op spaceDelimited(@body body: SpaceDelimitedArrayProperty): SpaceDelimitedArrayProperty; + + @route("/pipe-delimited") + @scenario + @scenarioDoc(""" + Test operation with request and response model contains a string array property with pipeDelimited encode. + Expected request body: + ```json + { + "value": "blue|red|green" + } + ``` + Expected response body: + ```json + { + "value": "blue|red|green" + } + ``` + """) + @post + op pipeDelimited(@body body: PipeDelimitedArrayProperty): PipeDelimitedArrayProperty; + + @route("/newline-delimited") + @scenario + @scenarioDoc(""" + Test operation with request and response model contains a string array property with newlineDelimited encode. + Expected request body: + ```json + { + "value": "blue\\nred\\ngreen" + } + ``` + Expected response body: + ```json + { + "value": "blue\\nred\\ngreen" + } + ``` + """) + @post + op newlineDelimited(@body body: NewlineDelimitedArrayProperty): NewlineDelimitedArrayProperty; +} diff --git a/packages/http-specs/specs/encode/array/mockapi.ts b/packages/http-specs/specs/encode/array/mockapi.ts new file mode 100644 index 00000000000..8b22eeb67ea --- /dev/null +++ b/packages/http-specs/specs/encode/array/mockapi.ts @@ -0,0 +1,43 @@ +import { json, passOnSuccess, ScenarioMockApi } from "@typespec/spec-api"; + +export const Scenarios: Record = {}; + +const colors = ["blue", "red", "green"]; + +function createPropertyServerTests(uri: string, delimiter: string) { + const encodedValue = colors.join(delimiter); + return passOnSuccess({ + uri, + method: "post", + request: { + body: json({ + value: encodedValue, + }), + }, + response: { + status: 200, + body: json({ value: encodedValue }), + }, + kind: "MockApiDefinition", + }); +} + +Scenarios.Encode_Array_Property_commaDelimited = createPropertyServerTests( + "/encode/array/property/comma-delimited", + ",", +); + +Scenarios.Encode_Array_Property_spaceDelimited = createPropertyServerTests( + "/encode/array/property/space-delimited", + " ", +); + +Scenarios.Encode_Array_Property_pipeDelimited = createPropertyServerTests( + "/encode/array/property/pipe-delimited", + "|", +); + +Scenarios.Encode_Array_Property_newlineDelimited = createPropertyServerTests( + "/encode/array/property/newline-delimited", + "\n", +); From 869089fcd38d6eb2b1a108e8cd3bac63fbb1c024 Mon Sep 17 00:00:00 2001 From: Fiona Date: Thu, 4 Dec 2025 12:59:13 -0500 Subject: [PATCH 02/40] Add transformer library to compiler package - Add transformer.ts with core transformer infrastructure - Integrate mutator framework for type transformations - Add TransformerDefinition, TransformDefinition types - Update program.ts to support transformers - Add transformer tester utilities - Add comprehensive transformer tests --- packages/compiler/src/config/config-schema.ts | 25 ++ packages/compiler/src/config/types.ts | 9 + packages/compiler/src/core/library.ts | 12 + packages/compiler/src/core/options.ts | 5 +- packages/compiler/src/core/program.ts | 47 +- packages/compiler/src/core/stats.ts | 6 + packages/compiler/src/core/transformer.ts | 282 ++++++++++++ packages/compiler/src/core/types.ts | 73 +++- packages/compiler/src/index.ts | 7 +- packages/compiler/src/testing/index.ts | 1 + packages/compiler/src/testing/tester.ts | 162 ++++++- packages/compiler/src/testing/types.ts | 51 ++- packages/compiler/test/core/linter.test.ts | 4 +- .../compiler/test/core/transformer.test.ts | 411 ++++++++++++++++++ packages/compiler/test/testing/tester.test.ts | 42 ++ 15 files changed, 1122 insertions(+), 15 deletions(-) create mode 100644 packages/compiler/src/core/transformer.ts create mode 100644 packages/compiler/test/core/transformer.test.ts diff --git a/packages/compiler/src/config/config-schema.ts b/packages/compiler/src/config/config-schema.ts index 0df1c8b9333..d1705f46947 100644 --- a/packages/compiler/src/config/config-schema.ts +++ b/packages/compiler/src/config/config-schema.ts @@ -103,5 +103,30 @@ export const TypeSpecConfigJsonSchema: JSONSchemaType = { }, }, } as any, // ajv type system doesn't like the string templates + transformer: { + type: "object", + nullable: true, + required: [], + additionalProperties: false, + properties: { + extends: { + type: "array", + nullable: true, + items: { type: "string" }, + }, + enable: { + type: "object", + required: [], + nullable: true, + additionalProperties: { type: "boolean" }, + }, + disable: { + type: "object", + required: [], + nullable: true, + additionalProperties: { type: "string" }, + }, + }, + } as any, // ajv type system doesn't like the string templates }, }; diff --git a/packages/compiler/src/config/types.ts b/packages/compiler/src/config/types.ts index f38d07a1173..66c6b5a4358 100644 --- a/packages/compiler/src/config/types.ts +++ b/packages/compiler/src/config/types.ts @@ -69,6 +69,8 @@ export interface TypeSpecConfig { options?: Record; linter?: LinterConfig; + + transformer?: TransformerConfig; } /** @@ -88,6 +90,7 @@ export interface TypeSpecRawConfig { options?: Record; linter?: LinterConfig; + transformer?: TransformerConfig; } export interface ConfigEnvironmentVariable { @@ -107,3 +110,9 @@ export interface LinterConfig { enable?: Record; disable?: Record; } + +export interface TransformerConfig { + extends?: RuleRef[]; + enable?: Record; + disable?: Record; +} diff --git a/packages/compiler/src/core/library.ts b/packages/compiler/src/core/library.ts index 24687c6f774..882400b8283 100644 --- a/packages/compiler/src/core/library.ts +++ b/packages/compiler/src/core/library.ts @@ -9,6 +9,8 @@ import { LinterRuleDefinition, PackageFlags, StateDef, + TransformDefinition, + TransformerDefinition, TypeSpecLibrary, TypeSpecLibraryDef, } from "./types.js"; @@ -116,6 +118,16 @@ export function createLinterRule(definition: TransformDefinition) { + compilerAssert(!definition.name.includes("/"), "Transform name cannot contain a '/'."); + return definition; +} + /** * Set the TypeSpec namespace for that function. * @param namespace Namespace string (e.g. "Foo.Bar") diff --git a/packages/compiler/src/core/options.ts b/packages/compiler/src/core/options.ts index 6f5d88140f1..7f40683855d 100644 --- a/packages/compiler/src/core/options.ts +++ b/packages/compiler/src/core/options.ts @@ -1,5 +1,5 @@ import { EmitterOptions, TypeSpecConfig } from "../config/types.js"; -import { LinterRuleSet, ParseOptions } from "./types.js"; +import { LinterRuleSet, ParseOptions, TransformSet } from "./types.js"; export interface CompilerOptions { miscOptions?: Record; @@ -68,6 +68,9 @@ export interface CompilerOptions { /** Ruleset to enable for linting. */ linterRuleSet?: LinterRuleSet; + /** Transform set to enable for transformation. */ + transformSet?: TransformSet; + /** @internal */ readonly configFile?: TypeSpecConfig; } diff --git a/packages/compiler/src/core/program.ts b/packages/compiler/src/core/program.ts index c0eeefb81fd..6db05776035 100644 --- a/packages/compiler/src/core/program.ts +++ b/packages/compiler/src/core/program.ts @@ -43,6 +43,12 @@ import { } from "./source-loader.js"; import { createStateAccessors } from "./state-accessors.js"; import { ComplexityStats, RuntimeStats, Stats, startTimer, time, timeAsync } from "./stats.js"; +import { + builtInTransformerLibraryName, + createBuiltInTransformerLibrary, + createTransformer, + resolveTransformerDefinition, +} from "./transformer.js"; import { CompilerHost, Diagnostic, @@ -52,8 +58,8 @@ import { EmitterFunc, Entity, JsSourceFileNode, - LibraryInstance, LibraryMetadata, + LinterLibraryInstance, LiteralType, LocationContext, LogSink, @@ -68,6 +74,7 @@ import { SyntaxKind, TemplateInstanceTarget, Tracer, + TransformerLibraryInstance, Type, TypeSpecLibrary, TypeSpecScriptNode, @@ -136,13 +143,20 @@ export interface Program { readonly projectRoot: string; } +export interface TransformedProgram extends Program { + /** + * Result from running transformers, including mutation engines for accessing transformed types. + */ + readonly transformerResult?: import("./transformer.js").TransformerResult; +} + interface EmitterRef { emitFunction: EmitterFunc; main: string; metadata: LibraryMetadata; emitterOutputDir: string; options: Record; - readonly library: LibraryInstance; + readonly library: LinterLibraryInstance & TransformerLibraryInstance; } interface Validator { @@ -207,7 +221,7 @@ async function createProgram( mainFile: string, options: CompilerOptions = {}, oldProgram?: Program, -): Promise<{ program: Program; shouldAbort: boolean }> { +): Promise<{ program: TransformedProgram; shouldAbort: boolean }> { const runtimeStats: Partial = {}; const validateCbs: Validator[] = []; const stateMaps = new Map>(); @@ -303,6 +317,16 @@ async function createProgram( program.reportDiagnostics(await linter.extendRuleSet(options.linterRuleSet)); } + const transformer = createTransformer(program, (name) => loadLibrary(basedir, name)); + // Register built-in transformer library (currently empty placeholder) + transformer.registerTransformLibrary( + builtInTransformerLibraryName, + createBuiltInTransformerLibrary(), + ); + if (options.transformSet) { + program.reportDiagnostics(await transformer.extendTransformSet(options.transformSet)); + } + program.checker = createChecker(program, resolver); runtimeStats.checker = time(() => program.checker.checkProgram()); @@ -329,7 +353,17 @@ async function createProgram( runtimeStats.linter = lintResult.stats.runtime; program.reportDiagnostics(lintResult.diagnostics); - return { program, shouldAbort: false }; + // Transform stage + const transformResult = transformer.transform(); + runtimeStats.transformer = transformResult.stats.runtime; + program.reportDiagnostics(transformResult.diagnostics); + + // Attach transformer result to the program so consumers can access mutation engines + const transformedProgram: TransformedProgram = Object.assign(transformResult.program, { + transformerResult: transformResult, + }); + + return { program: transformedProgram, shouldAbort: false }; /** * Validate the libraries loaded during the compilation process are compatible. @@ -507,7 +541,7 @@ async function createProgram( async function loadLibrary( basedir: string, libraryNameOrPath: string, - ): Promise { + ): Promise<(LinterLibraryInstance & TransformerLibraryInstance) | undefined> { const [resolution, diagnostics] = await resolveEmitterModuleAndEntrypoint( basedir, libraryNameOrPath, @@ -522,11 +556,14 @@ async function createProgram( const libDefinition: TypeSpecLibrary | undefined = entrypoint?.esmExports.$lib; const metadata = computeLibraryMetadata(module, libDefinition); const linterDef = entrypoint?.esmExports.$linter; + const transformerDef = entrypoint?.esmExports.$transformer; return { ...resolution, metadata, definition: libDefinition, linter: linterDef && resolveLinterDefinition(libraryNameOrPath, linterDef), + transformer: + transformerDef && resolveTransformerDefinition(libraryNameOrPath, transformerDef), }; } diff --git a/packages/compiler/src/core/stats.ts b/packages/compiler/src/core/stats.ts index 936339ad103..05ca4bf666f 100644 --- a/packages/compiler/src/core/stats.ts +++ b/packages/compiler/src/core/stats.ts @@ -25,6 +25,12 @@ export interface RuntimeStats { [rule: string]: number; }; }; + transformer: { + total: number; + transforms: { + [transform: string]: number; + }; + }; emit: { total: number; emitters: { diff --git a/packages/compiler/src/core/transformer.ts b/packages/compiler/src/core/transformer.ts new file mode 100644 index 00000000000..b7c1e2e5f87 --- /dev/null +++ b/packages/compiler/src/core/transformer.ts @@ -0,0 +1,282 @@ +import type { MutationEngine } from "@typespec/mutator-framework"; +import { compilerAssert, createDiagnosticCollector } from "./diagnostics.js"; +import type { Program, TransformedProgram } from "./program.js"; +import { startTimer } from "./stats.js"; +import { + Diagnostic, + NoTarget, + Transform, + TransformSet, + TransformSetRef, + TransformerDefinition, + TransformerResolvedDefinition, +} from "./types.js"; + +/** + * Minimal interface for transformer library data needed internally. + * The full TransformerLibraryInstance from types.ts includes module metadata + * that isn't needed for transformer registration. + */ +interface TransformerLibrary { + transformer: TransformerResolvedDefinition; +} + +export interface Transformer { + extendTransformSet(transformSet: TransformSet): Promise; + registerTransformLibrary(name: string, lib?: TransformerLibrary): void; + transform(): TransformerResult; + /** + * Get the mutation engine for a specific transform. + * Useful for debugging and inspecting transform state. + * @param transformId - The fully qualified transform ID (e.g., "library/transform-name") + * @returns The mutation engine if it exists, undefined otherwise + */ + getEngine(transformId: string): MutationEngine | undefined; +} + +export interface TransformerStats { + runtime: { + total: number; + transforms: Record; + engineCreation: Record; + }; +} +export interface TransformerResult { + readonly diagnostics: readonly Diagnostic[]; + readonly program: TransformedProgram; + readonly stats: TransformerStats; + readonly engines: ReadonlyMap>; +} + +/** Resolve a transformer definition for a library. */ +export function resolveTransformerDefinition( + libName: string, + transformer: TransformerDefinition, +): TransformerResolvedDefinition { + const transforms: Transform[] = transformer.transforms.map((t) => { + return { ...t, id: `${libName}/${t.name}` }; + }); + if ( + transformer.transforms.length === 0 || + (transformer.transformSets && "all" in transformer.transformSets) + ) { + return { + transforms, + transformSets: transformer.transformSets ?? {}, + }; + } else { + return { + transforms, + transformSets: { + all: { + enable: Object.fromEntries(transforms.map((x) => [x.id, true])) as any, + }, + ...transformer.transformSets, + }, + }; + } +} + +export function createTransformer( + program: Program, + loadLibrary: (name: string) => Promise, +): Transformer { + const tracer = program.tracer.sub("transformer"); + + const transformMap = new Map>(); + const enabledTransforms = new Map>(); + const transformerLibraries = new Map(); + const engines = new Map>(); + + return { + extendTransformSet, + registerTransformLibrary, + transform, + getEngine: (transformId: string) => engines.get(transformId), + }; + + async function extendTransformSet(transformSet: TransformSet): Promise { + tracer.trace("extend-transform-set.start", JSON.stringify(transformSet, null, 2)); + const diagnostics = createDiagnosticCollector(); + if (transformSet.extends) { + for (const extendingTransformSetName of transformSet.extends) { + const ref = parseTransformReference(extendingTransformSetName); + if (ref) { + const library = await resolveLibrary(ref.libraryName); + const libTransformerDefinition = library?.transformer; + const extendingTransformSet = libTransformerDefinition?.transformSets?.[ref.name]; + if (extendingTransformSet) { + await extendTransformSet(extendingTransformSet); + } else { + diagnostics.add({ + code: "unknown-transform-set", + message: `Unknown transform set '${ref.name}' in library '${ref.libraryName}'.`, + severity: "warning", + target: NoTarget, + } as Diagnostic); + } + } + } + } + + const enabledInThisSet = new Set(); + if (transformSet.enable) { + for (const [transformName, enable] of Object.entries(transformSet.enable)) { + if (enable === false) { + continue; + } + const ref = parseTransformReference(transformName as TransformSetRef); + if (ref) { + await resolveLibrary(ref.libraryName); + const transform = transformMap.get(transformName); + if (transform) { + enabledInThisSet.add(transformName); + enabledTransforms.set(transformName, transform); + } else { + diagnostics.add({ + code: "unknown-transform", + message: `Unknown transform '${ref.name}' in library '${ref.libraryName}'.`, + severity: "warning", + target: NoTarget, + } as Diagnostic); + } + } + } + } + + if (transformSet.disable) { + for (const transformName of Object.keys(transformSet.disable)) { + if (enabledInThisSet.has(transformName)) { + diagnostics.add({ + code: "transform-enabled-disabled", + message: `Transform '${transformName}' cannot be both enabled and disabled.`, + severity: "warning", + target: NoTarget, + } as Diagnostic); + } + enabledTransforms.delete(transformName); + } + } + tracer.trace( + "extend-transform-set.end", + "Transforms enabled: \n" + [...enabledTransforms.keys()].map((x) => ` - ${x}`).join("\n"), + ); + + return diagnostics.diagnostics; + } + + function transform(): TransformerResult { + const diagnostics = createDiagnosticCollector(); + const stats: TransformerStats = { + runtime: { + total: 0, + transforms: {}, + engineCreation: {}, + }, + }; + tracer.trace( + "transform", + `Running transformer with following transforms:\n` + + [...enabledTransforms.keys()].map((x) => ` - ${x}`).join("\n"), + ); + + const timer = startTimer(); + + // Step 1: Create mutation engines for all enabled transforms + for (const [id, t] of enabledTransforms.entries()) { + const engineTimer = startTimer(); + try { + tracer.trace("transform.create-engine", `Creating engine for ${id}`); + const engine = t.createEngine(program); + engines.set(id, engine); + stats.runtime.engineCreation[id] = engineTimer.end(); + tracer.trace("transform.engine-created", `Created engine for ${id}`); + } catch (error) { + diagnostics.add({ + code: "transform-engine-error", + message: `Failed to create mutation engine for transform '${id}': ${error}`, + severity: "error", + target: NoTarget, + }); + stats.runtime.engineCreation[id] = engineTimer.end(); + } + } + + // Step 2: Engines are now ready + // Note: With the mutator-framework, mutations are lazy - they happen when types are accessed, + // not upfront. The engines are stored and will be used when transformed types are requested. + // We don't need to actively "run" the transformations here. + for (const [id, _t] of enabledTransforms.entries()) { + const transformTimer = startTimer(); + tracer.trace("transform.ready", `Transform ${id} engine is ready for lazy mutation`); + stats.runtime.transforms[id] = transformTimer.end(); + } + + stats.runtime.total = timer.end(); + + // For now, return the original program as the transformed program placeholder. + // TODO: Create a true TransformedProgram that references the mutated type graph + return { + diagnostics: diagnostics.diagnostics, + program: program as TransformedProgram, + stats, + engines, + }; + } + + async function resolveLibrary(name: string): Promise { + const loadedLibrary = transformerLibraries.get(name); + if (loadedLibrary === undefined) { + return registerTransformLibrary(name); + } + return loadedLibrary; + } + + async function registerTransformLibrary( + name: string, + lib?: TransformerLibrary, + ): Promise { + tracer.trace("register-library", name); + + const library = lib ?? (await loadLibrary(name)); + const transformer = library?.transformer; + if (transformer?.transforms) { + for (const t of transformer.transforms) { + tracer.trace( + "register-library.transform", + `Registering transform "${t.id}" for library "${name}".`, + ); + if (transformMap.has(t.id)) { + compilerAssert(false, `Unexpected duplicate transform: "${t.id}"`); + } else { + transformMap.set(t.id, t); + } + } + } + transformerLibraries.set(name, library); + + return library; + } + + function parseTransformReference( + ref: TransformSetRef, + ): { libraryName: string; name: string } | undefined { + const segments = ref.split("/"); + const name = segments.pop(); + const libraryName = segments.join("/"); + if (!libraryName || !name) { + return undefined; + } + return { libraryName, name }; + } +} + +export const builtInTransformerLibraryName = `@typespec/compiler/transformers`; +export function createBuiltInTransformerLibrary(): TransformerLibrary { + // No built-in transforms yet; provide an empty definition. + const empty: TransformerResolvedDefinition = { + transforms: [], + transformSets: {}, + }; + return { transformer: empty }; +} diff --git a/packages/compiler/src/core/types.ts b/packages/compiler/src/core/types.ts index 7dd56a806a2..88a52b388ad 100644 --- a/packages/compiler/src/core/types.ts +++ b/packages/compiler/src/core/types.ts @@ -1,5 +1,6 @@ +import type { MutationEngine } from "@typespec/mutator-framework"; import type { JSONSchemaType as AjvJSONSchemaType } from "ajv"; -import type { ModuleResolutionResult } from "../module-resolver/index.js"; +import type { ModuleResolutionResult } from "../module-resolver/types.js"; import type { YamlPathTarget, YamlScript } from "../yaml/types.js"; import type { Numeric } from "./numeric.js"; import type { Program } from "./program.js"; @@ -1897,9 +1898,16 @@ export interface LibraryInstance { entrypoint: JsSourceFileNode; metadata: LibraryMetadata; definition?: TypeSpecLibrary; +} + +export interface LinterLibraryInstance extends LibraryInstance { linter: LinterResolvedDefinition; } +export interface TransformerLibraryInstance extends LibraryInstance { + transformer: TransformerResolvedDefinition; +} + export type LibraryMetadata = FileLibraryMetadata | ModuleLibraryMetadata; interface LibraryMetadataBase { @@ -2411,6 +2419,69 @@ export type LinterRuleDiagnosticReport< M extends keyof T = "default", > = LinterRuleDiagnosticReportWithoutTarget & { target: DiagnosticTarget | typeof NoTarget }; +export interface TransformerDefinition { + transforms: TransformDefinition[]; + transformSets?: Record; +} + +export interface TransformerResolvedDefinition { + readonly transforms: Transform[]; + readonly transformSets: { + [name: string]: TransformSet; + }; +} + +export interface TransformDefinition { + /** Transform name (without the library name) */ + name: N; + /** Short description of the transform */ + description: string; + /** Specifies the URL at which the full documentation can be accessed. */ + url?: string; + /** + * Factory function that creates a mutation engine for this transform. + * + * The mutation engine defines how types in the type graph should be transformed. + * It manages mutation nodes, subgraphs, and caching of transformed types. + * + * @param program - The TypeSpec program to transform + * @returns A mutation engine configured for this transform + * + * @example + * ```ts + * import { $ } from "@typespec/compiler/typekit"; + * import { SimpleMutationEngine, ModelMutation } from "@typespec/mutator-framework"; + * + * createEngine: (program) => { + * const tk = $(program); + * return new SimpleMutationEngine(tk, { + * Model: RenameModelMutation, + * }); + * } + * ``` + */ + createEngine: (program: Program) => MutationEngine; +} + +/** Resolved instance of a transform that will run. */ +export interface Transform extends TransformDefinition { + /** Expanded transform id in format `:` */ + id: string; +} + +/** Reference to a transform. In this format `:` */ +export type TransformSetRef = `${string}/${string}`; +export interface TransformSet { + /** Other transformset this transformset extends */ + extends?: TransformSetRef[]; + + /** Transforms to enable/configure */ + enable?: Record; + + /** Transforms to disable. A transform CANNOT be in enable and disable map. */ + disable?: Record; +} + export interface TypeSpecLibrary< T extends { [code: string]: DiagnosticMessages }, E extends Record = Record, diff --git a/packages/compiler/src/index.ts b/packages/compiler/src/index.ts index 55ae15c153d..4c9aee775b1 100644 --- a/packages/compiler/src/index.ts +++ b/packages/compiler/src/index.ts @@ -93,9 +93,11 @@ export { } from "./core/intrinsic-type-state.js"; export { createLinterRule as createRule, + createTransform, createTypeSpecLibrary, defineLinter, definePackageFlags, + defineTransformer, paramMessage, setTypeSpecNamespace, } from "./core/library.js"; @@ -359,12 +361,12 @@ export type { IntrinsicScalarName, IntrinsicType, JSONSchemaType, - LibraryInstance, LibraryLocationContext, LibraryMetadata, LineAndCharacter, LineComment, LinterDefinition, + LinterLibraryInstance, LinterResolvedDefinition, LinterRule, LinterRuleContext, @@ -440,6 +442,9 @@ export type { TextRange, Tracer, TracerOptions, + TransformDefinition, + TransformerDefinition, + TransformerLibraryInstance, Tuple, Type, TypeInstantiationMap, diff --git a/packages/compiler/src/testing/index.ts b/packages/compiler/src/testing/index.ts index 80fbe8465c0..8dc10a6f01f 100644 --- a/packages/compiler/src/testing/index.ts +++ b/packages/compiler/src/testing/index.ts @@ -42,6 +42,7 @@ export type { TestHostError, Tester, TesterInstance, + TransformerTesterInstance, TypeSpecTestLibrary, TypeSpecTestLibraryInit, } from "./types.js"; diff --git a/packages/compiler/src/testing/tester.ts b/packages/compiler/src/testing/tester.ts index 1d2aed77ea0..ccda0100f9a 100644 --- a/packages/compiler/src/testing/tester.ts +++ b/packages/compiler/src/testing/tester.ts @@ -1,3 +1,4 @@ +import { MutationOptions } from "@typespec/mutator-framework"; import { realpath } from "fs/promises"; import { pathToFileURL } from "url"; import { compilerAssert } from "../core/diagnostics.js"; @@ -8,7 +9,14 @@ import { getIdentifierContext, getNodeAtPosition } from "../core/parser.js"; import { getRelativePathFromDirectory, joinPaths, resolvePath } from "../core/path-utils.js"; import { Program, compile as coreCompile } from "../core/program.js"; import { createSourceLoader } from "../core/source-loader.js"; -import { CompilerHost, Diagnostic, Entity, NoTarget, SourceFile } from "../core/types.js"; +import { + CompilerHost, + Diagnostic, + Entity, + NoTarget, + SourceFile, + TransformSet, +} from "../core/types.js"; import { resolveModule } from "../module-resolver/module-resolver.js"; import { NodePackageResolver } from "../module-resolver/node-package-resolver.js"; import { ResolveModuleHost } from "../module-resolver/types.js"; @@ -19,7 +27,7 @@ import { createTestFileSystem } from "./fs.js"; import { GetMarkedEntities, Marker, TemplateWithMarkers } from "./marked-template.js"; import { StandardTestLibrary, addTestLib } from "./test-compiler-host.js"; import { resolveVirtualPath } from "./test-utils.js"; -import type { +import { EmitterTester, EmitterTesterInstance, MockFile, @@ -31,6 +39,8 @@ import type { Tester, TesterBuilder, TesterInstance, + TransformerTester, + TransformerTesterInstance, } from "./types.js"; export interface TesterOptions { @@ -163,6 +173,10 @@ interface EmitterTesterInternalParams extends TesterInternalParams { emitter: string; } +interface TransformerTesterInternalParams extends TesterInternalParams { + transformSet: TransformSet; +} + function createTesterBuilder< const I extends TesterInternalParams, const O extends TesterBuilder, @@ -227,6 +241,7 @@ function createTesterInternal(params: TesterInternalParams): Tester { ...createTesterBuilder(params, createTesterInternal), emit, createInstance, + transformer, }; function emit(emitter: string, options?: Record): EmitterTester { @@ -245,6 +260,16 @@ function createTesterInternal(params: TesterInternalParams): Tester { }); } + function transformer( + transformSet: TransformSet, + options?: Record, + ): TransformerTester { + return createTransformerTesterInternal({ + ...params, + transformSet, + }); + } + function createInstance(): Promise { return createTesterInstance(params); } @@ -274,6 +299,41 @@ function createEmitterTesterInternal( }; } +function createTransformerTesterInternal( + params: TransformerTesterInternalParams, +): TransformerTester { + return { + ...createCompilable(async (...args) => { + const instance = await createTransformerTesterInstance(params); + return instance.compileAndDiagnose(...args); + }), + ...createTesterBuilder( + params, + createTransformerTesterInternal, + ), + // transform, + createInstance: () => createTransformerTesterInstance(params), + }; + + // async function transform< + // T extends string | TemplateWithMarkers | Record>, + // >( + // code: T, + // options?: TestTransformOptions, + // ): Promise>> { + // const tester = await createTesterInstance(params); + // + // // todo + // return tester.compile(code, { + // ...options, + // compilerOptions: { + // ...(options ?? {}).compilerOptions, + // transformSet: params.transformSet, + // }, + // }); + // } +} + async function createEmitterTesterInstance( params: EmitterTesterInternalParams, ): Promise> { @@ -323,6 +383,37 @@ async function createEmitterTesterInstance( } } +async function createTransformerTesterInstance( + params: TransformerTesterInternalParams, +): Promise { + const tester = await createTesterInstance(params); + return { + fs: tester.fs, + ...createCompilable(compileAndDiagnose), + get program() { + return tester.program; + }, + }; + + async function compileAndDiagnose( + code: string | TemplateWithMarkers | Record>, + options?: TestCompileOptions, + ): Promise<[TestCompileResult, readonly Diagnostic[]]> { + if (options?.compilerOptions?.transformSet !== undefined) { + throw new Error("Cannot set transformSet in options."); + } + const resolvedOptions: TestCompileOptions = { + ...options, + compilerOptions: { + ...params.compilerOptions, + ...options?.compilerOptions, + transformSet: params.transformSet, + }, + }; + return tester.compileAndDiagnose(code, resolvedOptions); + } +} + async function createTesterInstance(params: TesterInternalParams): Promise { let savedProgram: Program | undefined; const fs = (await params.fs()).clone(); @@ -411,19 +502,84 @@ async function createTesterInstance(params: TesterInternalParams): Promise( + transformId: string, + type: TType, + ): TType => { + const transformedProgram = program as import("../core/program.js").TransformedProgram; + const engine = transformedProgram.transformerResult?.engines.get(transformId); + if (!engine) { + throw new Error( + `Transform "${transformId}" not found. Available transforms: ${Array.from(transformedProgram.transformerResult?.engines.keys() ?? []).join(", ")}`, + ); + } + // Get the default subgraph from the engine + const MutationOptionsClass = (engine as any).constructor.MutationOptions; + const options = MutationOptionsClass ? new MutationOptionsClass() : new MutationOptions(); + const subgraph = (engine as any).getDefaultMutationSubgraph?.(options); + if (!subgraph) { + throw new Error(`Engine for transform "${transformId}" does not have a default subgraph`); + } + // Type cast needed because tests use source types but mutator-framework uses compiled types + return engine.getMutatedType(subgraph as any, type as any) as TType; + }; + + // If transforms are enabled, automatically return mutated versions of entities + const transformedProgram = program as import("../core/program.js").TransformedProgram; + const mutatedEntities = + transformedProgram.transformerResult && transformedProgram.transformerResult.engines.size > 0 + ? applyAllTransforms(entities, transformedProgram) + : entities; + return [ { program, fs, pos: Object.fromEntries(markerPositions.map((x) => [x.name, x])) as any, + getMutatedType, ...(typesCollected as GetMarkedEntities), - ...entities, + ...mutatedEntities, }, program.diagnostics, ]; } } +function applyAllTransforms( + entities: Record, + transformedProgram: import("../core/program.js").TransformedProgram, +): Record { + if (!transformedProgram.transformerResult) return entities; + + const mutatedEntities: Record = {}; + const engines = Array.from(transformedProgram.transformerResult.engines.values()); + + for (const [name, entity] of Object.entries(entities)) { + // Apply all transformation engines in sequence + let mutated: any = entity; + if (entity.entityKind === "Type") { + for (const engine of engines) { + // Get the default mutation options + const MutationOptionsClass = (engine as any).constructor.MutationOptions; + const options = MutationOptionsClass ? new MutationOptionsClass() : new MutationOptions(); + + // Mutate the entity using the engine's mutate() method + // This triggers the Mutation class's mutate() method + // Type cast needed because tests use source types but mutator-framework uses compiled types + const mutation = (engine as any).mutate?.(mutated, options); + if (mutation) { + mutated = mutation.getMutatedType(); + } + } + } + mutatedEntities[name] = mutated; + } + + return mutatedEntities; +} + function extractMarkedEntities( program: Program, markerPositions: PositionedMarkerInFile[], diff --git a/packages/compiler/src/testing/types.ts b/packages/compiler/src/testing/types.ts index b35b08ac683..d1f42af4cef 100644 --- a/packages/compiler/src/testing/types.ts +++ b/packages/compiler/src/testing/types.ts @@ -1,6 +1,7 @@ +import { TransformerConfig } from "../config/index.js"; import type { CompilerOptions } from "../core/options.js"; -import type { Program } from "../core/program.js"; -import type { CompilerHost, Diagnostic, Entity, Type } from "../core/types.js"; +import type { Program, TransformedProgram } from "../core/program.js"; +import { CompilerHost, Diagnostic, Entity, TransformSet, Type } from "../core/types.js"; import { PositionedMarker } from "./fourslash.js"; import { GetMarkedEntities, TemplateWithMarkers } from "./marked-template.js"; @@ -58,6 +59,22 @@ export type TestCompileResult> = T & { /** Position of all markers */ readonly pos: Record; + + /** + * Get a mutated version of a type from a specific transform. + * This is used with lazy transformations where mutations are applied on-demand. + * + * @param transformId - The full transform ID (e.g., "@typespec/graphql/rename-types") + * @param type - The source type to get the mutated version of + * @returns The mutated type + * + * @example + * ```ts + * const result = await tester.compile(t.code`model ${t.model("Foo")} {}`); + * const mutatedFoo = result.getMutatedType("@typespec/graphql/rename-types", result.Foo); + * ``` + */ + getMutatedType?(transformId: string, type: TType): TType; } & Record; export interface TestCompileOptions { @@ -65,6 +82,8 @@ export interface TestCompileOptions { readonly compilerOptions?: CompilerOptions; } +export interface TestTransformOptions extends TestCompileOptions {} + interface Testable { /** * Compile the given code and validate no diagnostics(error or warnings) are present. @@ -146,6 +165,11 @@ export interface Tester extends Testable, TesterBuilder { * @param options - Options to pass to the emitter */ emit(emitter: string, options?: Record): EmitterTester; + /** + * Create a transformer tester + * @param options - Options to pass to the transformer + */ + transformer(transformSet: TransformSet, options?: TransformerConfig): TransformerTester; /** Create an instance of the tester */ createInstance(): Promise; } @@ -158,6 +182,11 @@ export interface TestEmitterCompileResult { readonly outputs: Record; } +export type TestTransformResult> = T & { + /** The program created in this transform. */ + readonly program: TransformedProgram; +} & Record; + export interface OutputTestable { compile(code: string | Record, options?: TestCompileOptions): Promise; compileAndDiagnose( @@ -193,6 +222,19 @@ export interface EmitterTester createInstance(): Promise>; } +/** Alternate version of the tester which runs the configured transformer */ +export interface TransformerTester extends Testable, TesterBuilder { + // transform< + // T extends string | TemplateWithMarkers | Record>, + // >( + // code: T, + // options?: TestTransformOptions, + // ): Promise>>; + + /** Create a mutable instance of the tester */ + createInstance(): Promise; +} + export interface TesterInstanceBase { /** Program created. Only available after calling `compile`, `diagnose` or `compileAndDiagnose` */ get program(): Program; @@ -211,6 +253,11 @@ export interface PositionedMarkerInFile extends PositionedMarker { readonly filename: string; } +/** Instance of a transformer tester */ +export interface TransformerTesterInstance extends TesterInstance { + get program(): TransformedProgram; +} + // #endregion // #region Legacy Test host diff --git a/packages/compiler/test/core/linter.test.ts b/packages/compiler/test/core/linter.test.ts index 36da211dedc..2e7a3b56df3 100644 --- a/packages/compiler/test/core/linter.test.ts +++ b/packages/compiler/test/core/linter.test.ts @@ -4,8 +4,8 @@ import { createLinterRule, createTypeSpecLibrary } from "../../src/core/library. import { Linter, createLinter, resolveLinterDefinition } from "../../src/core/linter.js"; import { type Interface, - type LibraryInstance, type LinterDefinition, + type LinterLibraryInstance, type LinterRuleContext, } from "../../src/index.js"; import { @@ -107,7 +107,7 @@ describe("compiler: linter", () => { } } - const library: LibraryInstance = { + const library: LinterLibraryInstance = { entrypoint: {} as any, metadata: { type: "module", name: "@typespec/test-linter" }, module: { type: "module", path: "", mainFile: "", manifest: { name: "", version: "" } }, diff --git a/packages/compiler/test/core/transformer.test.ts b/packages/compiler/test/core/transformer.test.ts new file mode 100644 index 00000000000..486fb797d2a --- /dev/null +++ b/packages/compiler/test/core/transformer.test.ts @@ -0,0 +1,411 @@ +import { describe, expect, it } from "vitest"; + +import { ModelMutation, SimpleMutationEngine } from "@typespec/mutator-framework"; +import { + builtInTransformerLibraryName, + createBuiltInTransformerLibrary, + createTransformer, + resolveTransformerDefinition, + Transformer, +} from "../../src/core/transformer.js"; +import type { TransformerDefinition, TransformerLibraryInstance } from "../../src/index.js"; +import { createTransform, createTypeSpecLibrary } from "../../src/index.js"; +import { + createTestHost, + expectDiagnosticEmpty, + expectDiagnostics, +} from "../../src/testing/index.js"; +import { $ } from "../../src/typekit/index.js"; + +const noopTransform = createTransform({ + name: "noop", + description: "No operation transform", + createEngine: (program) => { + // Create a simple mutation engine with no custom mutations + const tk = $(program) as any; + return new SimpleMutationEngine(tk, {}); + }, +}); + +// A transform that actually renames models by adding a prefix +class PrefixModelMutation extends ModelMutation { + mutate() { + this.mutateType((model) => { + model.name = `Prefixed${model.name}`; + }); + super.mutate(); + } +} + +const prefixTransform = createTransform({ + name: "prefix", + description: "Add prefix to model names", + createEngine: (program) => { + const tk = $(program) as any; + return new SimpleMutationEngine(tk, { + Model: PrefixModelMutation, + }); + }, +}); + +// A transform that throws during engine creation +const failingTransform = createTransform({ + name: "failing", + description: "Transform that fails during engine creation", + createEngine: (_program) => { + throw new Error("Intentional engine creation failure"); + }, +}); + +describe("compiler: transformer", () => { + async function createTestTransformer( + code: string | Record, + transformerDef: TransformerDefinition, + ): Promise { + const host = await createTestHost(); + if (typeof code === "string") { + host.addTypeSpecFile("main.tsp", code); + } else { + for (const [name, content] of Object.entries(code)) { + host.addTypeSpecFile(name, content); + } + } + + const library: TransformerLibraryInstance = { + entrypoint: {} as any, + metadata: { type: "module", name: "@typespec/test-transformer" }, + module: { type: "module", path: "", mainFile: "", manifest: { name: "", version: "" } }, + definition: createTypeSpecLibrary({ + name: "@typespec/test-transformer", + diagnostics: {}, + }), + transformer: resolveTransformerDefinition("@typespec/test-transformer", transformerDef), + }; + + await host.compile("main.tsp"); + + return createTransformer(host.program, (libName) => + Promise.resolve(libName === "@typespec/test-transformer" ? library : undefined), + ); + } + + it("registering a transform doesn't enable it", async () => { + const transformer = await createTestTransformer(`model Foo {}`, { + transforms: [noopTransform], + }); + expectDiagnosticEmpty(transformer.transform().diagnostics); + }); + + it("enabling a transform that doesn't exist emits a diagnostic", async () => { + const transformer = await createTestTransformer(`model Foo {}`, { + transforms: [noopTransform], + }); + expectDiagnostics( + await transformer.extendTransformSet({ + enable: { "@typespec/test-transformer/not-a-transform": true }, + }), + { + severity: "warning", + code: "unknown-transform", + message: `Unknown transform 'not-a-transform' in library '@typespec/test-transformer'.`, + }, + ); + }); + + it("enabling a transform set that doesn't exist emits a diagnostic", async () => { + const transformer = await createTestTransformer(`model Foo {}`, { + transforms: [noopTransform], + }); + expectDiagnostics( + await transformer.extendTransformSet({ extends: ["@typespec/test-transformer/not-a-set"] }), + { + severity: "warning", + code: "unknown-transform-set", + message: `Unknown transform set 'not-a-set' in library '@typespec/test-transformer'.`, + }, + ); + }); + + it("emits a diagnostic if enabling and disabling the same transform", async () => { + const transformer = await createTestTransformer(`model Foo {}`, { + transforms: [noopTransform], + }); + expectDiagnostics( + await transformer.extendTransformSet({ + enable: { "@typespec/test-transformer/noop": true }, + disable: { "@typespec/test-transformer/noop": "Reason" }, + }), + { + severity: "warning", + code: "transform-enabled-disabled", + message: `Transform '@typespec/test-transformer/noop' cannot be both enabled and disabled.`, + }, + ); + }); + + describe("when enabling a transform set", () => { + it("/all set is automatically provided and include all transforms", async () => { + const transformer = await createTestTransformer(`model Foo {}`, { + transforms: [noopTransform], + }); + expectDiagnosticEmpty( + await transformer.extendTransformSet({ + extends: ["@typespec/test-transformer/all"], + }), + ); + // No diagnostics expected from running transforms as noop transform doesn't report any. + expectDiagnosticEmpty(transformer.transform().diagnostics); + }); + + it("extending specific transform set enables the transforms inside", async () => { + const transformer = await createTestTransformer(`model Foo {}`, { + transforms: [noopTransform], + transformSets: { + custom: { + enable: { "@typespec/test-transformer/noop": true }, + }, + }, + }); + expectDiagnosticEmpty( + await transformer.extendTransformSet({ + extends: ["@typespec/test-transformer/custom"], + }), + ); + expectDiagnosticEmpty(transformer.transform().diagnostics); + }); + + it("nested extends enables transforms from both sets", async () => { + const transformer = await createTestTransformer(`model Foo {}`, { + transforms: [noopTransform, prefixTransform], + transformSets: { + base: { + enable: { "@typespec/test-transformer/noop": true }, + }, + extended: { + extends: ["@typespec/test-transformer/base"], + enable: { "@typespec/test-transformer/prefix": true }, + }, + }, + }); + expectDiagnosticEmpty( + await transformer.extendTransformSet({ + extends: ["@typespec/test-transformer/extended"], + }), + ); + const result = transformer.transform(); + expectDiagnosticEmpty(result.diagnostics); + // Both engines should be created + expect(result.engines.size).toBe(2); + }); + }); + + describe("disable functionality", () => { + it("disabling a transform from an extended set removes it", async () => { + const transformer = await createTestTransformer(`model Foo {}`, { + transforms: [noopTransform, prefixTransform], + transformSets: { + base: { + enable: { + "@typespec/test-transformer/noop": true, + "@typespec/test-transformer/prefix": true, + }, + }, + }, + }); + expectDiagnosticEmpty( + await transformer.extendTransformSet({ + extends: ["@typespec/test-transformer/base"], + disable: { "@typespec/test-transformer/noop": "Not needed" }, + }), + ); + const result = transformer.transform(); + expectDiagnosticEmpty(result.diagnostics); + // Only prefix transform should be enabled + expect(result.engines.size).toBe(1); + expect(transformer.getEngine("@typespec/test-transformer/prefix")).toBeDefined(); + expect(transformer.getEngine("@typespec/test-transformer/noop")).toBeUndefined(); + }); + + it("setting enable to false does not enable the transform", async () => { + const transformer = await createTestTransformer(`model Foo {}`, { + transforms: [noopTransform], + }); + expectDiagnosticEmpty( + await transformer.extendTransformSet({ + enable: { "@typespec/test-transformer/noop": false }, + }), + ); + const result = transformer.transform(); + expectDiagnosticEmpty(result.diagnostics); + expect(result.engines.size).toBe(0); + }); + }); + + describe("getEngine", () => { + it("returns undefined for non-existent transform", async () => { + const transformer = await createTestTransformer(`model Foo {}`, { + transforms: [noopTransform], + }); + expect(transformer.getEngine("@typespec/test-transformer/noop")).toBeUndefined(); + }); + + it("returns the engine after transform is enabled and run", async () => { + const transformer = await createTestTransformer(`model Foo {}`, { + transforms: [noopTransform], + }); + await transformer.extendTransformSet({ + enable: { "@typespec/test-transformer/noop": true }, + }); + transformer.transform(); + expect(transformer.getEngine("@typespec/test-transformer/noop")).toBeDefined(); + }); + }); + + describe("transform execution", () => { + it("creates engines for enabled transforms", async () => { + const transformer = await createTestTransformer(`model Foo {}`, { + transforms: [noopTransform], + }); + await transformer.extendTransformSet({ + enable: { "@typespec/test-transformer/noop": true }, + }); + const result = transformer.transform(); + expectDiagnosticEmpty(result.diagnostics); + expect(result.engines.size).toBe(1); + expect(result.engines.has("@typespec/test-transformer/noop")).toBe(true); + }); + + it("tracks engine creation time in stats", async () => { + const transformer = await createTestTransformer(`model Foo {}`, { + transforms: [noopTransform], + }); + await transformer.extendTransformSet({ + enable: { "@typespec/test-transformer/noop": true }, + }); + const result = transformer.transform(); + expect(result.stats.runtime.engineCreation["@typespec/test-transformer/noop"]).toBeDefined(); + expect(result.stats.runtime.total).toBeGreaterThanOrEqual(0); + }); + + it("runs multiple transforms in sequence", async () => { + const transformer = await createTestTransformer(`model Foo {}`, { + transforms: [noopTransform, prefixTransform], + }); + await transformer.extendTransformSet({ + enable: { + "@typespec/test-transformer/noop": true, + "@typespec/test-transformer/prefix": true, + }, + }); + const result = transformer.transform(); + expectDiagnosticEmpty(result.diagnostics); + expect(result.engines.size).toBe(2); + }); + + it("emits diagnostic when engine creation fails", async () => { + const transformer = await createTestTransformer(`model Foo {}`, { + transforms: [failingTransform], + }); + await transformer.extendTransformSet({ + enable: { "@typespec/test-transformer/failing": true }, + }); + const result = transformer.transform(); + expectDiagnostics(result.diagnostics, { + code: "transform-engine-error", + severity: "error", + message: /Failed to create mutation engine.*Intentional engine creation failure/, + }); + }); + }); + + describe("transform that mutates types", () => { + it("creates engine that can mutate model names", async () => { + const transformer = await createTestTransformer(`model Foo { x: string; }`, { + transforms: [prefixTransform], + }); + await transformer.extendTransformSet({ + enable: { "@typespec/test-transformer/prefix": true }, + }); + const result = transformer.transform(); + expectDiagnosticEmpty(result.diagnostics); + + const engine = result.engines.get("@typespec/test-transformer/prefix"); + expect(engine).toBeDefined(); + + // Get the Foo model from the program + const Foo = result.program.getGlobalNamespaceType().models.get("Foo"); + expect(Foo).toBeDefined(); + + // Use the engine to get the mutated type + const mutation = engine!.mutate(Foo! as any); + const mutatedFoo = mutation.getMutatedType(); + expect(mutatedFoo.name).toBe("PrefixedFoo"); + }); + }); +}); + +describe("resolveTransformerDefinition", () => { + it("adds library prefix to transform ids", () => { + const resolved = resolveTransformerDefinition("@my/lib", { + transforms: [noopTransform], + }); + expect(resolved.transforms[0].id).toBe("@my/lib/noop"); + }); + + it("auto-generates 'all' transform set when not provided", () => { + const resolved = resolveTransformerDefinition("@my/lib", { + transforms: [noopTransform], + }); + expect(resolved.transformSets.all).toBeDefined(); + expect(resolved.transformSets.all.enable).toEqual({ + "@my/lib/noop": true, + }); + }); + + it("does not override existing 'all' transform set", () => { + const resolved = resolveTransformerDefinition("@my/lib", { + transforms: [noopTransform], + transformSets: { + all: { + enable: { "@my/lib/custom": true }, + }, + }, + }); + expect(resolved.transformSets.all.enable).toEqual({ + "@my/lib/custom": true, + }); + }); + + it("preserves custom transform sets", () => { + const resolved = resolveTransformerDefinition("@my/lib", { + transforms: [noopTransform], + transformSets: { + custom: { + enable: { "@my/lib/noop": true }, + }, + }, + }); + expect(resolved.transformSets.custom).toBeDefined(); + expect(resolved.transformSets.all).toBeDefined(); + }); + + it("handles empty transforms array", () => { + const resolved = resolveTransformerDefinition("@my/lib", { + transforms: [], + }); + expect(resolved.transforms).toHaveLength(0); + expect(resolved.transformSets).toEqual({}); + }); +}); + +describe("createBuiltInTransformerLibrary", () => { + it("returns an empty transformer definition", () => { + const lib = createBuiltInTransformerLibrary(); + expect(lib.transformer.transforms).toHaveLength(0); + expect(lib.transformer.transformSets).toEqual({}); + }); + + it("has the correct library name", () => { + expect(builtInTransformerLibraryName).toBe("@typespec/compiler/transformers"); + }); +}); diff --git a/packages/compiler/test/testing/tester.test.ts b/packages/compiler/test/testing/tester.test.ts index 819f98623db..33df821c8a8 100644 --- a/packages/compiler/test/testing/tester.test.ts +++ b/packages/compiler/test/testing/tester.test.ts @@ -1,9 +1,12 @@ // TODO: rename? +import { SimpleMutationEngine } from "@typespec/mutator-framework"; import { strictEqual } from "assert"; import { describe, expect, expectTypeOf, it } from "vitest"; import { resolvePath } from "../../src/core/path-utils.js"; import { + createTransform, + defineTransformer, EmitContext, emitFile, Enum, @@ -17,6 +20,7 @@ import { mockFile } from "../../src/testing/fs.js"; import { t } from "../../src/testing/marked-template.js"; import { resolveVirtualPath } from "../../src/testing/test-utils.js"; import { createTester } from "../../src/testing/tester.js"; +import { $ } from "../../src/typekit/index.js"; const Tester = createTester(resolvePath(import.meta.dirname, "../.."), { libraries: [] }); @@ -357,3 +361,41 @@ describe("emitter", () => { }); }); }); + +describe("transformer", () => { + const TransformerTester = Tester.files({ + "node_modules/dummy-transformer/package.json": JSON.stringify({ + name: "dummy-transformer", + version: "1.0.0", + exports: { ".": "./index.js" }, + }), + "node_modules/dummy-transformer/index.js": mockFile.js({ + $transformer: defineTransformer({ + transforms: [ + createTransform({ + name: "dummy-transform", + description: "A dummy transform.", + createEngine: (program) => { + const tk = $(program); + return new SimpleMutationEngine(tk, {}); + }, + }), + ], + }), + }), + }).transformer({ extends: ["dummy-transformer/all"] }); + + it("can transform", async () => { + const result = await TransformerTester.compile(t.code` + model ${t.model("Foo")} {} + `); + expect(result.Foo.kind).toBe("Model"); + }); + + it("can wrap", async () => { + const result = await TransformerTester.wrap( + (x) => `model Test {}\n${x}\nmodel Test2 {}`, + ).compile(t.code`model ${t.model("Foo")} {}`); + expect(result.Foo.kind).toBe("Model"); + }); +}); From 3a1ac827959124dd93adbefb26491fe398bc4501 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 4 Dec 2025 18:29:18 +0000 Subject: [PATCH 03/40] Bump jws from 3.2.2 to 3.2.3 in /packages/http-client-csharp (#9140) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [jws](https://github.com/brianloveswords/node-jws) from 3.2.2 to 3.2.3.
Release notes

Sourced from jws's releases.

v3.2.3

Changed

  • Fix advisory GHSA-869p-cjfg-cm3x: createSign and createVerify now require that a non empty secret is provided (via opts.secret, opts.privateKey or opts.key) when using HMAC algorithms.
  • Upgrading JWA version to 1.4.2, addressing a compatibility issue for Node >= 25.
Changelog

Sourced from jws's changelog.

[3.2.3]

Changed

  • Fix advisory GHSA-869p-cjfg-cm3x: createSign and createVerify now require that a non empty secret is provided (via opts.secret, opts.privateKey or opts.key) when using HMAC algorithms.
  • Upgrading JWA version to 1.4.2, adressing a compatibility issue for Node >= 25.

[3.0.0]

Changed

2.0.0 - 2015-01-30

Changed

  • BREAKING: Default payload encoding changed from binary to utf8. utf8 is a is a more sensible default than binary because many payloads, as far as I can tell, will contain user-facing strings that could be in any language. (6b6de48)

  • Code reorganization, thanks @​fearphage! (7880050)

Added

  • Option in all relevant methods for encoding. For those few users that might be depending on a binary encoding of the messages, this is for them. (6b6de48)
Commits
  • 4f6e73f Merge commit from fork
  • bd0fea5 version 3.2.3
  • 7c3b4b4 Enhance tests for HMAC streaming sign and verify
  • a9b8ed9 Improve secretOrKey initialization in VerifyStream
  • 6707fde Improve secret handling in SignStream
  • See full diff in compare view
Maintainer changes

This version was pushed to npm by julien.wollscheid, a new releaser for jws since your current version.


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=jws&package-manager=npm_and_yarn&previous-version=3.2.2&new-version=3.2.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/microsoft/typespec/network/alerts).
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- packages/http-client-csharp/package-lock.json | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/http-client-csharp/package-lock.json b/packages/http-client-csharp/package-lock.json index c79ff06169b..7dc6de2be4b 100644 --- a/packages/http-client-csharp/package-lock.json +++ b/packages/http-client-csharp/package-lock.json @@ -2066,6 +2066,7 @@ "integrity": "sha512-Fll2FZ1riMjNmlmJOdAyY5pUbkftXslB5DgEzlIuNaiWhXd00FhWxVC/r4yV/4wBb9JfImTu+jiSvXTkJ7F/gA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~6.20.0" } @@ -2096,6 +2097,7 @@ "integrity": "sha512-yxyV+ch8tnqiuU2gClv/mQEESoFwpkjo6177UkYfV0nVA9PzTg4zVVc7+WIMZk04wiLRRT3H1uc11FB1cwLY3g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "~7.27.1", "@inquirer/prompts": "^7.4.0", @@ -2272,6 +2274,7 @@ "integrity": "sha512-q/JwVw21CF4buE3ZS+xSoy2TKAOwyhZ7g3kdNqCgm69BI5p5GGu+3ZlUA+4Blk8hkt0G8XcIN8fhJP+a4O6KAw==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=20.0.0" }, @@ -2343,6 +2346,7 @@ "integrity": "sha512-KuxYAzfP5ljM0PUhSGclNZgTG0H+kyTQcwn6cf4TKhO72R2QMQmiMtN2plqvzsfkL+TLwad1iZhMWTCAMFAQ4w==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=20.0.0" }, @@ -2357,6 +2361,7 @@ "integrity": "sha512-6jtQWdcmuKyG9cmqWsJjaq64f6N5B/1DS4X3ZoTNgYhHA27Hnsxo1HZWXcpv7Wl+MxLAZM6kgpML0ugDEZcrYQ==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=20.0.0" }, @@ -2587,6 +2592,7 @@ "integrity": "sha512-7gQPtsokyn0Mjr43MAik6ZkQt1PZjseU+KcBE2iGT9P6oWYYTH3K1C4LLGXHZAbgEtBvFn4S+U8HPbDhj4nEhw==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=20.0.0" }, @@ -2743,6 +2749,7 @@ "integrity": "sha512-dguO/B+mwlCyenWGG+M+16cMQuGHSTJbU5Z0pyUou1uyWrB1px//s4pW7PKD14S+fPutJE0wTMQm+CctOq6quA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=20.0.0" }, @@ -2756,6 +2763,7 @@ "integrity": "sha512-+I7hdWZDO3qBfzRT3St+1Dg/NQAMNLz8w1OydutSnVMx0G3KWg/ESonaByszBUfdq6Z5iTtls3gvj4wgrw80gA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=20.0.0" }, @@ -2876,6 +2884,7 @@ "integrity": "sha512-hGISOaP18plkzbWEcP/QvtRW1xDXF2+96HbEX6byqQhAUbiS5oH6/9JwW+QsQCIYON2bI6QZBF+2PvOmrRZ9wA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@vitest/utils": "3.2.4", "fflate": "^0.8.2", @@ -2954,6 +2963,7 @@ "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -5213,13 +5223,13 @@ } }, "node_modules/jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.3.tgz", + "integrity": "sha512-byiJ0FLRdLdSVSReO/U4E7RoEyOCKnEnEPMjq3HxWtvzLsV08/i5RQKsFVNkCldrCaPr2vDNAOMsfs8T/Hze7g==", "dev": true, "license": "MIT", "dependencies": { - "jwa": "^1.4.1", + "jwa": "^1.4.2", "safe-buffer": "^5.0.1" } }, @@ -7365,6 +7375,7 @@ "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -7495,26 +7506,13 @@ "url": "https://opencollective.com/vitest" } }, - "node_modules/vite-node/node_modules/@types/node": { - "version": "24.1.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.1.0.tgz", - "integrity": "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "undici-types": "~7.8.0" - } - }, "node_modules/vite-node/node_modules/undici-types": { "version": "7.8.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz", "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==", "dev": true, "license": "MIT", - "optional": true, - "peer": true + "optional": true }, "node_modules/vite-node/node_modules/vite": { "version": "7.0.6", @@ -7597,6 +7595,7 @@ "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/chai": "^5.2.2", "@vitest/expect": "3.2.4", @@ -7697,6 +7696,7 @@ "integrity": "sha512-MHFiOENNBd+Bd9uvc8GEsIzdkn1JxMmEeYX35tI3fv0sJBUTfW5tQsoaOwuY4KhBI09A3dUJ/DXf2yxPVPUceg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.6", From 3168ad73d6d5485ffa637e9517b95380fe3223db Mon Sep 17 00:00:00 2001 From: Fiona Date: Thu, 4 Dec 2025 14:31:48 -0500 Subject: [PATCH 04/40] Add better diagnostic handling and various cleanup --- packages/compiler/src/config/types.ts | 8 +- packages/compiler/src/core/messages.ts | 34 +++++ packages/compiler/src/core/stats.ts | 5 +- packages/compiler/src/core/transformer.ts | 125 +++++++++++------- packages/compiler/src/testing/tester.ts | 19 --- packages/compiler/src/testing/types.ts | 14 -- .../compiler/test/core/transformer.test.ts | 27 +++- 7 files changed, 139 insertions(+), 93 deletions(-) diff --git a/packages/compiler/src/config/types.ts b/packages/compiler/src/config/types.ts index 66c6b5a4358..e6c76c907b3 100644 --- a/packages/compiler/src/config/types.ts +++ b/packages/compiler/src/config/types.ts @@ -1,4 +1,4 @@ -import type { Diagnostic, RuleRef } from "../core/types.js"; +import type { Diagnostic, RuleRef, TransformSetRef } from "../core/types.js"; import type { YamlScript } from "../yaml/types.js"; /** @@ -112,7 +112,7 @@ export interface LinterConfig { } export interface TransformerConfig { - extends?: RuleRef[]; - enable?: Record; - disable?: Record; + extends?: TransformSetRef[]; + enable?: Record; + disable?: Record; } diff --git a/packages/compiler/src/core/messages.ts b/packages/compiler/src/core/messages.ts index 5c42d275d59..7b580f2566d 100644 --- a/packages/compiler/src/core/messages.ts +++ b/packages/compiler/src/core/messages.ts @@ -761,6 +761,40 @@ const diagnostics = { }, }, + /** + * Transformer + */ + "invalid-transform-ref": { + severity: "error", + messages: { + default: paramMessage`Reference "${"ref"}" is not a valid reference to a transform or transform set. It must be in the following format: "/"`, + }, + }, + "unknown-transform": { + severity: "warning", + messages: { + default: paramMessage`Transform "${"transformName"}" is not found in library "${"libraryName"}"`, + }, + }, + "unknown-transform-set": { + severity: "warning", + messages: { + default: paramMessage`Transform set "${"transformSetName"}" is not found in library "${"libraryName"}"`, + }, + }, + "transform-enabled-disabled": { + severity: "warning", + messages: { + default: paramMessage`Transform "${"transformName"}" has been enabled and disabled in the same transform set.`, + }, + }, + "transform-engine-error": { + severity: "error", + messages: { + default: paramMessage`Failed to create mutation engine for transform "${"transformId"}": ${"error"}`, + }, + }, + /** * Formatter */ diff --git a/packages/compiler/src/core/stats.ts b/packages/compiler/src/core/stats.ts index 05ca4bf666f..cc00b059457 100644 --- a/packages/compiler/src/core/stats.ts +++ b/packages/compiler/src/core/stats.ts @@ -26,9 +26,10 @@ export interface RuntimeStats { }; }; transformer: { + enabledTransforms: readonly string[]; total: number; - transforms: { - [transform: string]: number; + engineCreation: { + [transformId: string]: number; }; }; emit: { diff --git a/packages/compiler/src/core/transformer.ts b/packages/compiler/src/core/transformer.ts index b7c1e2e5f87..c9b5154da81 100644 --- a/packages/compiler/src/core/transformer.ts +++ b/packages/compiler/src/core/transformer.ts @@ -1,5 +1,6 @@ import type { MutationEngine } from "@typespec/mutator-framework"; import { compilerAssert, createDiagnosticCollector } from "./diagnostics.js"; +import { createDiagnostic } from "./messages.js"; import type { Program, TransformedProgram } from "./program.js"; import { startTimer } from "./stats.js"; import { @@ -22,13 +23,30 @@ interface TransformerLibrary { } export interface Transformer { + /** + * Extend the current transform set with additional transforms. + * @param transformSet - The transform set configuration to apply + * @returns Diagnostics from processing the transform set + */ extendTransformSet(transformSet: TransformSet): Promise; - registerTransformLibrary(name: string, lib?: TransformerLibrary): void; + + /** + * Register a transformer library. + * @param name - The library name + * @param lib - Optional library instance (will be loaded if not provided) + */ + registerTransformLibrary(name: string, lib?: TransformerLibrary): Promise; + + /** + * Execute all enabled transforms and create mutation engines. + * @returns The transformation result including diagnostics, program, and engines + */ transform(): TransformerResult; + /** * Get the mutation engine for a specific transform. * Useful for debugging and inspecting transform state. - * @param transformId - The fully qualified transform ID (e.g., "library/transform-name") + * @param transformId - The fully qualified transform ID (e.g., "@library/transform-name") * @returns The mutation engine if it exists, undefined otherwise */ getEngine(transformId: string): MutationEngine | undefined; @@ -36,8 +54,11 @@ export interface Transformer { export interface TransformerStats { runtime: { + /** List of transform IDs that were enabled */ + enabledTransforms: readonly string[]; + /** Total time for all transform operations in milliseconds */ total: number; - transforms: Record; + /** Time spent creating each engine, keyed by transform ID */ engineCreation: Record; }; } @@ -65,12 +86,15 @@ export function resolveTransformerDefinition( transformSets: transformer.transformSets ?? {}, }; } else { + // Auto-generate an 'all' transform set that enables all transforms + const allEnable: Record = {}; + for (const t of transforms) { + allEnable[t.id as TransformSetRef] = true; + } return { transforms, transformSets: { - all: { - enable: Object.fromEntries(transforms.map((x) => [x.id, true])) as any, - }, + all: { enable: allEnable }, ...transformer.transformSets, }, }; @@ -90,7 +114,9 @@ export function createTransformer( return { extendTransformSet, - registerTransformLibrary, + registerTransformLibrary: async (name: string, lib?: TransformerLibrary) => { + await registerTransformLibraryInternal(name, lib); + }, transform, getEngine: (transformId: string) => engines.get(transformId), }; @@ -100,7 +126,7 @@ export function createTransformer( const diagnostics = createDiagnosticCollector(); if (transformSet.extends) { for (const extendingTransformSetName of transformSet.extends) { - const ref = parseTransformReference(extendingTransformSetName); + const ref = diagnostics.pipe(parseTransformReference(extendingTransformSetName)); if (ref) { const library = await resolveLibrary(ref.libraryName); const libTransformerDefinition = library?.transformer; @@ -108,12 +134,13 @@ export function createTransformer( if (extendingTransformSet) { await extendTransformSet(extendingTransformSet); } else { - diagnostics.add({ - code: "unknown-transform-set", - message: `Unknown transform set '${ref.name}' in library '${ref.libraryName}'.`, - severity: "warning", - target: NoTarget, - } as Diagnostic); + diagnostics.add( + createDiagnostic({ + code: "unknown-transform-set", + format: { libraryName: ref.libraryName, transformSetName: ref.name }, + target: NoTarget, + }), + ); } } } @@ -125,7 +152,7 @@ export function createTransformer( if (enable === false) { continue; } - const ref = parseTransformReference(transformName as TransformSetRef); + const ref = diagnostics.pipe(parseTransformReference(transformName as TransformSetRef)); if (ref) { await resolveLibrary(ref.libraryName); const transform = transformMap.get(transformName); @@ -133,12 +160,13 @@ export function createTransformer( enabledInThisSet.add(transformName); enabledTransforms.set(transformName, transform); } else { - diagnostics.add({ - code: "unknown-transform", - message: `Unknown transform '${ref.name}' in library '${ref.libraryName}'.`, - severity: "warning", - target: NoTarget, - } as Diagnostic); + diagnostics.add( + createDiagnostic({ + code: "unknown-transform", + format: { libraryName: ref.libraryName, transformName: ref.name }, + target: NoTarget, + }), + ); } } } @@ -147,12 +175,13 @@ export function createTransformer( if (transformSet.disable) { for (const transformName of Object.keys(transformSet.disable)) { if (enabledInThisSet.has(transformName)) { - diagnostics.add({ - code: "transform-enabled-disabled", - message: `Transform '${transformName}' cannot be both enabled and disabled.`, - severity: "warning", - target: NoTarget, - } as Diagnostic); + diagnostics.add( + createDiagnostic({ + code: "transform-enabled-disabled", + format: { transformName }, + target: NoTarget, + }), + ); } enabledTransforms.delete(transformName); } @@ -167,22 +196,23 @@ export function createTransformer( function transform(): TransformerResult { const diagnostics = createDiagnosticCollector(); + const enabledTransformIds = [...enabledTransforms.keys()]; const stats: TransformerStats = { runtime: { + enabledTransforms: enabledTransformIds, total: 0, - transforms: {}, engineCreation: {}, }, }; tracer.trace( "transform", `Running transformer with following transforms:\n` + - [...enabledTransforms.keys()].map((x) => ` - ${x}`).join("\n"), + enabledTransformIds.map((x) => ` - ${x}`).join("\n"), ); const timer = startTimer(); - // Step 1: Create mutation engines for all enabled transforms + // Create mutation engines for all enabled transforms for (const [id, t] of enabledTransforms.entries()) { const engineTimer = startTimer(); try { @@ -192,30 +222,22 @@ export function createTransformer( stats.runtime.engineCreation[id] = engineTimer.end(); tracer.trace("transform.engine-created", `Created engine for ${id}`); } catch (error) { - diagnostics.add({ - code: "transform-engine-error", - message: `Failed to create mutation engine for transform '${id}': ${error}`, - severity: "error", - target: NoTarget, - }); + diagnostics.add( + createDiagnostic({ + code: "transform-engine-error", + format: { transformId: id, error: String(error) }, + target: NoTarget, + }), + ); stats.runtime.engineCreation[id] = engineTimer.end(); } } - // Step 2: Engines are now ready // Note: With the mutator-framework, mutations are lazy - they happen when types are accessed, // not upfront. The engines are stored and will be used when transformed types are requested. - // We don't need to actively "run" the transformations here. - for (const [id, _t] of enabledTransforms.entries()) { - const transformTimer = startTimer(); - tracer.trace("transform.ready", `Transform ${id} engine is ready for lazy mutation`); - stats.runtime.transforms[id] = transformTimer.end(); - } stats.runtime.total = timer.end(); - // For now, return the original program as the transformed program placeholder. - // TODO: Create a true TransformedProgram that references the mutated type graph return { diagnostics: diagnostics.diagnostics, program: program as TransformedProgram, @@ -227,12 +249,12 @@ export function createTransformer( async function resolveLibrary(name: string): Promise { const loadedLibrary = transformerLibraries.get(name); if (loadedLibrary === undefined) { - return registerTransformLibrary(name); + return registerTransformLibraryInternal(name); } return loadedLibrary; } - async function registerTransformLibrary( + async function registerTransformLibraryInternal( name: string, lib?: TransformerLibrary, ): Promise { @@ -260,14 +282,17 @@ export function createTransformer( function parseTransformReference( ref: TransformSetRef, - ): { libraryName: string; name: string } | undefined { + ): [{ libraryName: string; name: string } | undefined, readonly Diagnostic[]] { const segments = ref.split("/"); const name = segments.pop(); const libraryName = segments.join("/"); if (!libraryName || !name) { - return undefined; + return [ + undefined, + [createDiagnostic({ code: "invalid-transform-ref", format: { ref }, target: NoTarget })], + ]; } - return { libraryName, name }; + return [{ libraryName, name }, []]; } } diff --git a/packages/compiler/src/testing/tester.ts b/packages/compiler/src/testing/tester.ts index ccda0100f9a..7795ae46b03 100644 --- a/packages/compiler/src/testing/tester.ts +++ b/packages/compiler/src/testing/tester.ts @@ -311,27 +311,8 @@ function createTransformerTesterInternal( params, createTransformerTesterInternal, ), - // transform, createInstance: () => createTransformerTesterInstance(params), }; - - // async function transform< - // T extends string | TemplateWithMarkers | Record>, - // >( - // code: T, - // options?: TestTransformOptions, - // ): Promise>> { - // const tester = await createTesterInstance(params); - // - // // todo - // return tester.compile(code, { - // ...options, - // compilerOptions: { - // ...(options ?? {}).compilerOptions, - // transformSet: params.transformSet, - // }, - // }); - // } } async function createEmitterTesterInstance( diff --git a/packages/compiler/src/testing/types.ts b/packages/compiler/src/testing/types.ts index d1f42af4cef..72a3e572457 100644 --- a/packages/compiler/src/testing/types.ts +++ b/packages/compiler/src/testing/types.ts @@ -82,8 +82,6 @@ export interface TestCompileOptions { readonly compilerOptions?: CompilerOptions; } -export interface TestTransformOptions extends TestCompileOptions {} - interface Testable { /** * Compile the given code and validate no diagnostics(error or warnings) are present. @@ -182,11 +180,6 @@ export interface TestEmitterCompileResult { readonly outputs: Record; } -export type TestTransformResult> = T & { - /** The program created in this transform. */ - readonly program: TransformedProgram; -} & Record; - export interface OutputTestable { compile(code: string | Record, options?: TestCompileOptions): Promise; compileAndDiagnose( @@ -224,13 +217,6 @@ export interface EmitterTester /** Alternate version of the tester which runs the configured transformer */ export interface TransformerTester extends Testable, TesterBuilder { - // transform< - // T extends string | TemplateWithMarkers | Record>, - // >( - // code: T, - // options?: TestTransformOptions, - // ): Promise>>; - /** Create a mutable instance of the tester */ createInstance(): Promise; } diff --git a/packages/compiler/test/core/transformer.test.ts b/packages/compiler/test/core/transformer.test.ts index 486fb797d2a..c50b21e8329 100644 --- a/packages/compiler/test/core/transformer.test.ts +++ b/packages/compiler/test/core/transformer.test.ts @@ -17,11 +17,14 @@ import { } from "../../src/testing/index.js"; import { $ } from "../../src/typekit/index.js"; +// Note: `as any` casts are needed below because test files use source types from src/ +// while @typespec/mutator-framework uses compiled types from dist/. This is a common +// TypeScript monorepo issue that doesn't affect runtime behavior. + const noopTransform = createTransform({ name: "noop", description: "No operation transform", createEngine: (program) => { - // Create a simple mutation engine with no custom mutations const tk = $(program) as any; return new SimpleMutationEngine(tk, {}); }, @@ -107,7 +110,7 @@ describe("compiler: transformer", () => { { severity: "warning", code: "unknown-transform", - message: `Unknown transform 'not-a-transform' in library '@typespec/test-transformer'.`, + message: /not-a-transform.*@typespec\/test-transformer/, }, ); }); @@ -121,7 +124,7 @@ describe("compiler: transformer", () => { { severity: "warning", code: "unknown-transform-set", - message: `Unknown transform set 'not-a-set' in library '@typespec/test-transformer'.`, + message: /not-a-set.*@typespec\/test-transformer/, }, ); }); @@ -138,7 +141,7 @@ describe("compiler: transformer", () => { { severity: "warning", code: "transform-enabled-disabled", - message: `Transform '@typespec/test-transformer/noop' cannot be both enabled and disabled.`, + message: /@typespec\/test-transformer\/noop.*enabled.*disabled/, }, ); }); @@ -287,6 +290,22 @@ describe("compiler: transformer", () => { expect(result.stats.runtime.total).toBeGreaterThanOrEqual(0); }); + it("includes enabled transforms in stats", async () => { + const transformer = await createTestTransformer(`model Foo {}`, { + transforms: [noopTransform, prefixTransform], + }); + await transformer.extendTransformSet({ + enable: { + "@typespec/test-transformer/noop": true, + "@typespec/test-transformer/prefix": true, + }, + }); + const result = transformer.transform(); + expect(result.stats.runtime.enabledTransforms).toContain("@typespec/test-transformer/noop"); + expect(result.stats.runtime.enabledTransforms).toContain("@typespec/test-transformer/prefix"); + expect(result.stats.runtime.enabledTransforms).toHaveLength(2); + }); + it("runs multiple transforms in sequence", async () => { const transformer = await createTestTransformer(`model Foo {}`, { transforms: [noopTransform, prefixTransform], From 9d36399467552cabb0efae447ad9552bc4873acc Mon Sep 17 00:00:00 2001 From: Alan Zimmer <48699787+alzimmermsft@users.noreply.github.com> Date: Thu, 4 Dec 2025 20:48:58 -0500 Subject: [PATCH 05/40] Cleanup some Java TypeSpec tests (#9132) Adds validation test for `module-info.java` formatting and cleans up partial update tests. --- .../http-client-generator-core/pom.xml | 36 ++ .../core/mapper/JavagenUnitTests.java | 17 - .../util/PartialUpdateHandlerTest.java | 579 ++++++------------ .../CodeFormatterUtilTests.java | 40 ++ .../core/util/ModelTestCaseUtilTests.java | 4 +- .../generator/core/util/SchemaUtilTests.java | 14 +- packages/http-client-java/generator/pom.xml | 8 + 7 files changed, 270 insertions(+), 428 deletions(-) delete mode 100644 packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/mapper/JavagenUnitTests.java create mode 100644 packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/postprocessor/implementation/CodeFormatterUtilTests.java 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 59ba660d8c0..2015b776104 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 @@ -20,6 +20,36 @@ ../ + + + + org.apache.maven.plugins + maven-resources-plugin + 3.3.1 + + + copy-eclipse-format-settings + generate-test-resources + + copy-resources + + + target/test-classes + + + ../ + + eclipse-format-azure-sdk-for-java.xml + + + + + + + + + + io.clientcore @@ -171,5 +201,11 @@ 5.13.4 test + + org.junit.jupiter + junit-jupiter-params + 5.13.4 + test + diff --git a/packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/mapper/JavagenUnitTests.java b/packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/mapper/JavagenUnitTests.java deleted file mode 100644 index 836dd0597de..00000000000 --- a/packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/mapper/JavagenUnitTests.java +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.microsoft.typespec.http.client.generator.core.mapper; - -/** - * unit test entry - */ -public class JavagenUnitTests { - - /** - * Test the correctness of generated returnType javadoc. - * It consists of two dimensions: - * 1. whether description exists already on operation or schema itself - * 2. when baseType and returnType varies - */ -} diff --git a/packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/partialupdate/util/PartialUpdateHandlerTest.java b/packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/partialupdate/util/PartialUpdateHandlerTest.java index 36e46def2c5..b8740567fe4 100644 --- a/packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/partialupdate/util/PartialUpdateHandlerTest.java +++ b/packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/partialupdate/util/PartialUpdateHandlerTest.java @@ -10,18 +10,21 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import com.github.javaparser.TokenRange; import com.github.javaparser.ast.AccessSpecifier; import com.github.javaparser.ast.CompilationUnit; +import com.github.javaparser.ast.body.BodyDeclaration; import com.github.javaparser.ast.body.ConstructorDeclaration; -import com.github.javaparser.ast.body.InitializerDeclaration; -import com.github.javaparser.ast.stmt.BlockStmt; +import com.github.javaparser.ast.body.MethodDeclaration; +import com.github.javaparser.ast.body.TypeDeclaration; +import com.github.javaparser.ast.modules.ModuleDeclaration; import java.io.IOException; import java.net.URISyntaxException; -import java.nio.charset.StandardCharsets; +import java.net.URL; import java.nio.file.Files; import java.nio.file.Paths; -import java.util.Arrays; import java.util.List; +import java.util.Objects; import java.util.stream.Collectors; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -30,13 +33,8 @@ public class PartialUpdateHandlerTest { @Test public void testClassOrInterfaceFileToTestAddMemberToExistingFile() throws IOException, URISyntaxException { - String existingFileContent = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader() - .getResource("partialupdate/StringOperationWithAddedMemberClient.java") - .toURI())), StandardCharsets.UTF_8); - String generatedFileContent = new String( - Files.readAllBytes(Paths.get( - getClass().getClassLoader().getResource("partialupdate/StringOperationGeneratedClient.java").toURI())), - StandardCharsets.UTF_8); + String existingFileContent = load("partialupdate/StringOperationWithAddedMemberClient.java"); + String generatedFileContent = load("partialupdate/StringOperationGeneratedClient.java"); String output = PartialUpdateHandler.handlePartialUpdateForFile(generatedFileContent, existingFileContent); @@ -56,43 +54,25 @@ public void testClassOrInterfaceFileToTestAddMemberToExistingFile() throws IOExc @Test public void testClassOrInterfaceFileToTestUpdateMethodSignatureToExistingFile() throws URISyntaxException, IOException { - String existingFileContent = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader() - .getResource("partialupdate/StringOperationWithUpdateMemberClient.java") - .toURI())), StandardCharsets.UTF_8); - String generatedFileContent = new String( - Files.readAllBytes(Paths.get( - getClass().getClassLoader().getResource("partialupdate/StringOperationGeneratedClient.java").toURI())), - StandardCharsets.UTF_8); + String existingFileContent = load("partialupdate/StringOperationWithUpdateMemberClient.java"); + String generatedFileContent = load("partialupdate/StringOperationGeneratedClient.java"); String output = PartialUpdateHandler.handlePartialUpdateForFile(generatedFileContent, existingFileContent); CompilationUnit compilationUnit = parse(output); assertEquals(1, compilationUnit.getTypes().size()); - assertEquals(1, compilationUnit.getTypes().get(0).getMethodsByName("putNullWithResponse").size()); - assertEquals(2, - compilationUnit.getTypes().get(0).getMethodsByName("putNullWithResponse").get(0).getParameters().size()); - assertEquals("test", - compilationUnit.getTypes() - .get(0) - .getMethodsByName("putNullWithResponse") - .get(0) - .getParameters() - .get(1) - .getName() - .asString()); - assertEquals(AccessSpecifier.NONE, - compilationUnit.getTypes().get(0).getMethodsByName("putNullWithResponse").get(0).getAccessSpecifier()); + List methods = compilationUnit.getTypes().get(0).getMethodsByName("putNullWithResponse"); + assertEquals(1, methods.size()); + MethodDeclaration method = methods.get(0); + assertEquals(2, method.getParameters().size()); + assertEquals("test", method.getParameters().get(1).getNameAsString()); + assertEquals(AccessSpecifier.NONE, method.getAccessSpecifier()); } @Test public void testClassOrInterfaceFileToTestRemoveMethodToExistingFile() throws URISyntaxException, IOException { - String existingFileContent = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader() - .getResource("partialupdate/StringOperationWithRemovedMemberGeneratedClient.java") - .toURI())), StandardCharsets.UTF_8); - String generatedFileContent = new String( - Files.readAllBytes(Paths.get( - getClass().getClassLoader().getResource("partialupdate/StringOperationGeneratedClient.java").toURI())), - StandardCharsets.UTF_8); + String existingFileContent = load("partialupdate/StringOperationWithRemovedMemberGeneratedClient.java"); + String generatedFileContent = load("partialupdate/StringOperationGeneratedClient.java"); String output = PartialUpdateHandler.handlePartialUpdateForFile(generatedFileContent, existingFileContent); @@ -105,13 +85,8 @@ public void testClassOrInterfaceFileToTestRemoveMethodToExistingFile() throws UR @Test public void testClassOrInterfaceFileToTestSawaggerAddAPI() throws URISyntaxException, IOException { - String existingFileContent = new String( - Files.readAllBytes(Paths.get( - getClass().getClassLoader().getResource("partialupdate/StringOperationGeneratedClient.java").toURI())), - StandardCharsets.UTF_8); - String generatedFileContent = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader() - .getResource("partialupdate/StringOperationWithAddedMemberGeneratedClient.java") - .toURI())), StandardCharsets.UTF_8); + String existingFileContent = load("partialupdate/StringOperationGeneratedClient.java"); + String generatedFileContent = load("partialupdate/StringOperationWithAddedMemberGeneratedClient.java"); String output = PartialUpdateHandler.handlePartialUpdateForFile(generatedFileContent, existingFileContent); @@ -123,13 +98,8 @@ public void testClassOrInterfaceFileToTestSawaggerAddAPI() throws URISyntaxExcep @Test public void testClassOrInterfaceFileToTestGeneratedFileRemoveAPI() throws URISyntaxException, IOException { - String existingFileContent = new String( - Files.readAllBytes(Paths.get( - getClass().getClassLoader().getResource("partialupdate/StringOperationGeneratedClient.java").toURI())), - StandardCharsets.UTF_8); - String generatedFileContent = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader() - .getResource("partialupdate/StringOperationWithRemovedMemberGeneratedClient.java") - .toURI())), StandardCharsets.UTF_8); + String existingFileContent = load("partialupdate/StringOperationGeneratedClient.java"); + String generatedFileContent = load("partialupdate/StringOperationWithRemovedMemberGeneratedClient.java"); String output = PartialUpdateHandler.handlePartialUpdateForFile(generatedFileContent, existingFileContent); @@ -140,160 +110,109 @@ public void testClassOrInterfaceFileToTestGeneratedFileRemoveAPI() throws URISyn @Test public void testClassOrInterfaceFileToTestGeneratedFileUpdateAPI() throws URISyntaxException, IOException { - String existingFileContent = new String( - Files.readAllBytes(Paths.get( - getClass().getClassLoader().getResource("partialupdate/StringOperationGeneratedClient.java").toURI())), - StandardCharsets.UTF_8); - String generatedFileContent = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader() - .getResource("partialupdate/StringOperationWithUpdateMemberGeneratedClient.java") - .toURI())), StandardCharsets.UTF_8); + String existingFileContent = load("partialupdate/StringOperationGeneratedClient.java"); + String generatedFileContent = load("partialupdate/StringOperationWithUpdateMemberGeneratedClient.java"); String output = PartialUpdateHandler.handlePartialUpdateForFile(generatedFileContent, existingFileContent); CompilationUnit compilationUnit = parse(output); assertEquals(1, compilationUnit.getTypes().size()); assertEquals(1, compilationUnit.getTypes().get(0).getMethods().size()); - assertEquals(1, compilationUnit.getTypes().get(0).getMethodsByName("putNullWithResponse").size()); - assertEquals("updateParam", - compilationUnit.getTypes() - .get(0) - .getMethodsByName("putNullWithResponse") - .get(0) - .getParameter(1) - .getName() - .asString()); + List methods = compilationUnit.getTypes().get(0).getMethodsByName("putNullWithResponse"); + assertEquals(1, methods.size()); + assertEquals("updateParam", methods.get(0).getParameter(1).getNameAsString()); } @Test public void testClassOrInterfaceFileToTestGeneratedFileUpdateAPIAndExistingFileUpdateMethod() throws URISyntaxException, IOException { - String existingFileContent = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader() - .getResource("partialupdate/StringOperationWithUpdateMemberClient.java") - .toURI())), StandardCharsets.UTF_8); - String generatedFileContent = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader() - .getResource("partialupdate/StringOperationWithUpdateMemberGeneratedClient.java") - .toURI())), StandardCharsets.UTF_8); + String existingFileContent = load("partialupdate/StringOperationWithUpdateMemberClient.java"); + String generatedFileContent = load("partialupdate/StringOperationWithUpdateMemberGeneratedClient.java"); String output = PartialUpdateHandler.handlePartialUpdateForFile(generatedFileContent, existingFileContent); CompilationUnit compilationUnit = parse(output); assertEquals(1, compilationUnit.getTypes().size()); assertEquals(1, compilationUnit.getTypes().get(0).getMethods().size()); - assertEquals(1, compilationUnit.getTypes().get(0).getMethodsByName("putNullWithResponse").size()); - assertEquals("test", - compilationUnit.getTypes() - .get(0) - .getMethodsByName("putNullWithResponse") - .get(0) - .getParameter(1) - .getName() - .asString()); - assertEquals(AccessSpecifier.NONE, - compilationUnit.getTypes().get(0).getMethodsByName("putNullWithResponse").get(0).getAccessSpecifier()); + List methods = compilationUnit.getTypes().get(0).getMethodsByName("putNullWithResponse"); + assertEquals(1, methods.size()); + MethodDeclaration method = methods.get(0); + assertEquals("test", method.getParameter(1).getNameAsString()); + assertEquals(AccessSpecifier.NONE, method.getAccessSpecifier()); } @Test public void testClassOrInterfaceFileToTestGeneratedFileRemoveAPIAndExistingFileUpdateMethod() throws URISyntaxException, IOException { - String existingFileContent = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader() - .getResource("partialupdate/StringOperationWithUpdateMemberClient.java") - .toURI())), StandardCharsets.UTF_8); - String generatedFileContent = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader() - .getResource("partialupdate/StringOperationWithRemovedMemberGeneratedClient.java") - .toURI())), StandardCharsets.UTF_8); + String existingFileContent = load("partialupdate/StringOperationWithUpdateMemberClient.java"); + String generatedFileContent = load("partialupdate/StringOperationWithRemovedMemberGeneratedClient.java"); String output = PartialUpdateHandler.handlePartialUpdateForFile(generatedFileContent, existingFileContent); CompilationUnit compilationUnit = parse(output); assertEquals(1, compilationUnit.getTypes().size()); assertEquals(1, compilationUnit.getTypes().get(0).getMethods().size()); - assertEquals(1, compilationUnit.getTypes().get(0).getMethodsByName("putNullWithResponse").size()); - assertEquals("test", - compilationUnit.getTypes() - .get(0) - .getMethodsByName("putNullWithResponse") - .get(0) - .getParameter(1) - .getName() - .asString()); + List methods = compilationUnit.getTypes().get(0).getMethodsByName("putNullWithResponse"); + assertEquals(1, methods.size()); + assertEquals("test", methods.get(0).getParameter(1).getNameAsString()); } @Test public void testClassOrInterfaceFileToTestWhenGeneratedFileHasSameNameButDifferentSignatureWithExistingGeneratedMethodToTestThenShouldIncludeThisSameNameMethod() throws URISyntaxException, IOException { - String existingFileContent = new String( - Files.readAllBytes(Paths - .get(getClass().getClassLoader().getResource("partialupdate/PagedGeneratedAsyncClient.java").toURI())), - StandardCharsets.UTF_8); - String generatedFileContent = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader() - .getResource("partialupdate/PagedGeneratedAsyncClientWithConvenienceMethod.java") - .toURI())), StandardCharsets.UTF_8); + String existingFileContent = load("partialupdate/PagedGeneratedAsyncClient.java"); + String generatedFileContent = load("partialupdate/PagedGeneratedAsyncClientWithConvenienceMethod.java"); String output = PartialUpdateHandler.handlePartialUpdateForFile(generatedFileContent, existingFileContent); CompilationUnit compilationUnit = parse(output); assertEquals(1, compilationUnit.getTypes().size()); - assertEquals(4, compilationUnit.getTypes().get(0).getMembers().size()); - assertEquals(1, compilationUnit.getTypes().get(0).getConstructors().size()); - assertEquals(1, compilationUnit.getTypes().get(0).getFields().size()); - assertEquals(2, compilationUnit.getTypes().get(0).getMethods().size()); - assertEquals(2, compilationUnit.getTypes().get(0).getMethodsByName("list").size()); + TypeDeclaration type = compilationUnit.getTypes().get(0); + assertEquals(4, type.getMembers().size()); + assertEquals(1, type.getConstructors().size()); + assertEquals(1, type.getFields().size()); + assertEquals(2, type.getMethods().size()); + assertEquals(2, type.getMethodsByName("list").size()); } @Test public void testClassOrInterfaceFileToTestWhenNoChangesAreMadeOnNextGenerationToTestThenTheFileShouldStaySame() throws URISyntaxException, IOException { - String existingFileContent = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader() - .getResource("partialupdate/PagedGeneratedAsyncClientWithConvenienceMethod.java") - .toURI())), StandardCharsets.UTF_8); - String generatedFileContent = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader() - .getResource("partialupdate/PagedGeneratedAsyncClientWithConvenienceMethod.java") - .toURI())), StandardCharsets.UTF_8); + String existingFileContent = load("partialupdate/PagedGeneratedAsyncClientWithConvenienceMethod.java"); + String generatedFileContent = load("partialupdate/PagedGeneratedAsyncClientWithConvenienceMethod.java"); String output = PartialUpdateHandler.handlePartialUpdateForFile(generatedFileContent, existingFileContent); CompilationUnit compilationUnit = parse(output); assertEquals(1, compilationUnit.getTypes().size()); - assertEquals(4, compilationUnit.getTypes().get(0).getMembers().size()); - assertEquals(1, compilationUnit.getTypes().get(0).getConstructors().size()); - assertEquals(1, compilationUnit.getTypes().get(0).getFields().size()); - assertEquals(2, compilationUnit.getTypes().get(0).getMethods().size()); - assertEquals(2, compilationUnit.getTypes().get(0).getMethodsByName("list").size()); + TypeDeclaration type = compilationUnit.getTypes().get(0); + assertEquals(4, type.getMembers().size()); + assertEquals(1, type.getConstructors().size()); + assertEquals(1, type.getFields().size()); + assertEquals(2, type.getMethods().size()); + assertEquals(2, type.getMethodsByName("list").size()); } @Test public void testClassOrInterfaceFileToTestVerifyGeneratedFileShouldNotContainDuplicateMethods() throws URISyntaxException, IOException { - String existingFileContent = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader() - .getResource("partialupdate/StringOperationWithDuplicateMethodGeneratedClient.java") - .toURI())), StandardCharsets.UTF_8); - String generatedFileContent = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader() - .getResource("partialupdate/StringOperationWithDuplicateMethodGeneratedClient.java") - .toURI())), StandardCharsets.UTF_8); - - Exception exception = assertThrows(RuntimeException.class, () -> { - PartialUpdateHandler.handlePartialUpdateForFile(generatedFileContent, existingFileContent); - }); + String existingFileContent = load("partialupdate/StringOperationWithDuplicateMethodGeneratedClient.java"); + String generatedFileContent = load("partialupdate/StringOperationWithDuplicateMethodGeneratedClient.java"); - String expectedMessage = "Found duplicate methods in the generated file."; - String actualMessage = exception.getMessage(); + Exception exception = assertThrows(RuntimeException.class, + () -> PartialUpdateHandler.handlePartialUpdateForFile(generatedFileContent, existingFileContent)); - assertTrue(actualMessage.contains(expectedMessage)); + assertTrue(exception.getMessage().contains("Found duplicate methods in the generated file.")); } @Test public void testClassOrInterfaceFileToTestModelCustomization() throws URISyntaxException, IOException { - String existingFileContent = new String( - Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("partialupdate/Model.java").toURI())), - StandardCharsets.UTF_8); - String generatedFileContent = new String( - Files.readAllBytes( - Paths.get(getClass().getClassLoader().getResource("partialupdate/GeneratedModel.java").toURI())), - StandardCharsets.UTF_8); + String existingFileContent = load("partialupdate/Model.java"); + String generatedFileContent = load("partialupdate/GeneratedModel.java"); String output = PartialUpdateHandler.handlePartialUpdateForFile(generatedFileContent, existingFileContent); @@ -309,18 +228,18 @@ public void testClassOrInterfaceFileToTestModelCustomization() throws URISyntaxE @Test public void testModuleInfoFileToTestWhenGeneratedFileEqualsExistingFileToTestThenUseGeneratedFile() { String existingFileContent = "// Copyright (c) Microsoft Corporation. All rights reserved.\n" - + "// Licensed under the MIT License.\n" + "// Code generated by Microsoft (R) AutoRest Code Generator.\n" - + "\n" + "module com.azure.iot.deviceupdate {\n" + "\n" + " requires transitive com.azure.core;\n" + "\n" - + " exports com.azure.iot.deviceupdate;\n" + "}\n"; + + "// Licensed under the MIT License.\n// Code generated by Microsoft (R) AutoRest Code Generator.\n\n" + + "module com.azure.iot.deviceupdate {\n\n requires transitive com.azure.core;\n\n" + + " exports com.azure.iot.deviceupdate;\n}\n\n"; String generatedFileContent = "// Copyright (c) Microsoft Corporation. All rights reserved.\n" - + "// Licensed under the MIT License.\n" + "// Code generated by Microsoft (R) AutoRest Code Generator.\n" - + "\n" + "module com.azure.iot.deviceupdate {\n" + "\n" + " requires transitive com.azure.core;\n" + "\n" - + " exports com.azure.iot.deviceupdate;\n" + "}\n"; + + "// Licensed under the MIT License.\n" + "// Code generated by Microsoft (R) AutoRest Code Generator.\n\n" + + "module com.azure.iot.deviceupdate {\n\n requires transitive com.azure.core;\n\n" + + " exports com.azure.iot.deviceupdate;\n}\n"; String output = PartialUpdateHandler.handlePartialUpdateForFile(generatedFileContent, existingFileContent); CompilationUnit compilationUnit = parse(output); - assertEquals(true, compilationUnit.getModule().isPresent()); + assertTrue(compilationUnit.getModule().isPresent()); assertEquals("com.azure.iot.deviceupdate", compilationUnit.getModule().get().getName().toString()); assertEquals(2, compilationUnit.getModule().get().getDirectives().size()); } @@ -328,21 +247,20 @@ public void testModuleInfoFileToTestWhenGeneratedFileEqualsExistingFileToTestThe @Test public void testModuleInfoFileToTestWhenExistingFileHasUpdatesToTestThenUseExistingFile() { String existingFileContent = "// Copyright (c) Microsoft Corporation. All rights reserved.\n" - + "// Licensed under the MIT License.\n" + "// Code generated by Microsoft (R) AutoRest Code Generator.\n" - + "\n" + "\n" + "module com.azure.messaging.webpubsubnew {\n" + " requires transitive com.azure.core;\n" - + "\n" + " exports com.azure.messaging.webpubsubnew;\n" - + " exports com.azure.messaging.webpubsubnew.models;\n" + "}"; + + "// Licensed under the MIT License.\n// Code generated by Microsoft (R) AutoRest Code Generator.\n\n\n" + + "module com.azure.messaging.webpubsubnew {\n requires transitive com.azure.core;\n\n" + + " exports com.azure.messaging.webpubsubnew;\n exports com.azure.messaging.webpubsubnew.models;\n}"; String generatedFileContent = "// Copyright (c) Microsoft Corporation. All rights reserved.\n" - + "// Licensed under the MIT License.\n" + "// Code generated by Microsoft (R) AutoRest Code Generator.\n" - + "\n" + "\n" + "module com.azure.messaging.webpubsubnew {\n" + " requires transitive com.azure.core;\n" - + "\n" + " exports com.azure.messaging.webpubsubnew;\n" + "}"; + + "// Licensed under the MIT License.\n// Code generated by Microsoft (R) AutoRest Code Generator.\n\n\n" + + "module com.azure.messaging.webpubsubnew {\n requires transitive com.azure.core;\n\n" + + " exports com.azure.messaging.webpubsubnew;\n}"; String output = PartialUpdateHandler.handlePartialUpdateForFile(generatedFileContent, existingFileContent); CompilationUnit compilationUnit = parse(output); assertNotNull(compilationUnit.getOrphanComments()); assertEquals(3, compilationUnit.getOrphanComments().size()); - assertEquals(true, compilationUnit.getModule().isPresent()); + assertTrue(compilationUnit.getModule().isPresent()); assertEquals("com.azure.messaging.webpubsubnew", compilationUnit.getModule().get().getName().toString()); assertEquals(3, compilationUnit.getModule().get().getDirectives().size()); } @@ -351,259 +269,121 @@ public void testModuleInfoFileToTestWhenExistingFileHasUpdatesToTestThenUseExist public void testModuleInfoFileToTestMergeExistingFileAndGeneratedFileToTestWhenExistingFileContentHasMoreDirectives() { String existingFileContent = "// Copyright (c) Microsoft Corporation. All rights reserved.\n" - + "// Licensed under the MIT License.\n" + "// Code generated by Microsoft (R) AutoRest Code Generator.\n" - + "module com.azure.messaging.webpubsubnew {\n" + " requires transitive com.azure.core;\n" + "\n" - + " exports com.azure.messaging.webpubsubnew;\n" - + " exports com.azure.messaging.webpubsubnew.models;\n" + "}"; + + "// Licensed under the MIT License.\n// Code generated by Microsoft (R) AutoRest Code Generator.\n" + + "module com.azure.messaging.webpubsubnew {\n requires transitive com.azure.core;\n\n" + + " exports com.azure.messaging.webpubsubnew;\n exports com.azure.messaging.webpubsubnew.models;\n}"; String generatedFileContent = "// Copyright (c) Microsoft Corporation. All rights reserved.\n" - + "// Licensed under the MIT License.\n" + "// Code generated by Microsoft (R) AutoRest Code Generator.\n" - + "module com.azure.messaging.webpubsubnew {\n" + " requires transitive com.azure.core;\n" + "\n" - + " exports com.azure.messaging.webpubsubnew;\n" + "}"; + + "// Licensed under the MIT License.\n// Code generated by Microsoft (R) AutoRest Code Generator.\n" + + "module com.azure.messaging.webpubsubnew {\n requires transitive com.azure.core;\n\n" + + " exports com.azure.messaging.webpubsubnew;\n}"; String output = PartialUpdateHandler.handlePartialUpdateForFile(generatedFileContent, existingFileContent); CompilationUnit compilationUnit = parse(output); - assertEquals(true, compilationUnit.getModule().isPresent()); - assertEquals("com.azure.messaging.webpubsubnew", compilationUnit.getModule().get().getName().toString()); - assertEquals(3, compilationUnit.getModule().get().getDirectives().size()); - assertEquals("requires transitive com.azure.core;", - compilationUnit.getModule() - .get() - .getDirectives() - .get(0) - .asModuleRequiresDirective() - .getTokenRange() - .get() - .toString()); - assertEquals("exports com.azure.messaging.webpubsubnew;", - compilationUnit.getModule() - .get() - .getDirectives() - .get(1) - .asModuleExportsDirective() - .getTokenRange() - .get() - .toString()); - assertEquals("exports com.azure.messaging.webpubsubnew.models;", - compilationUnit.getModule() - .get() - .getDirectives() - .get(2) - .asModuleExportsDirective() - .getTokenRange() - .get() - .toString()); - + ModuleDeclaration module = compilationUnit.getModule().orElseThrow(); + assertEquals("com.azure.messaging.webpubsubnew", module.getName().toString()); + assertEquals(3, module.getDirectives().size()); + assertEquals("requires transitive com.azure.core;", moduleDirectiveToString(module, 0)); + assertEquals("exports com.azure.messaging.webpubsubnew;", moduleDirectiveToString(module, 1)); + assertEquals("exports com.azure.messaging.webpubsubnew.models;", moduleDirectiveToString(module, 2)); } @Test public void testModuleInfoFileToTestMergeExistingFileAndGeneratedFileToTestWhenGeneratedFileContentHasMoreDirectives() { - String existingFileContent - = "module com.azure.communication.phonenumbersdemo {\n" + " requires transitive com.azure.core;\n" + "\n" - + " exports com.azure.communication.phonenumbersdemo;\n" + "}"; - String generatedFileContent - = "" + "module com.azure.communication.phonenumbersdemo {\n" + " requires transitive com.azure.core;\n" - + "\n" + " exports com.azure.communication.phonenumbersdemo;\n" - + " exports com.azure.communication.phonenumbersdemo.models;\n" + "\n" - + " opens com.azure.communication.phonenumbersdemo.implementation.models to\n" - + " com.azure.core,\n" + " com.fasterxml.jackson.databind;\n" - + " opens com.azure.communication.phonenumbersdemo.models to\n" + " com.azure.core,\n" - + " com.fasterxml.jackson.databind;\n" + "}"; + String existingFileContent = "module com.azure.communication.phonenumbersdemo {\n" + + " requires transitive com.azure.core;\n\n exports com.azure.communication.phonenumbersdemo;\n}"; + String generatedFileContent = "module com.azure.communication.phonenumbersdemo {\n" + + " requires transitive com.azure.core;\n\n exports com.azure.communication.phonenumbersdemo;\n" + + " exports com.azure.communication.phonenumbersdemo.models;\n\n" + + " opens com.azure.communication.phonenumbersdemo.implementation.models to\n" + + " com.azure.core,\n com.fasterxml.jackson.databind;\n" + + " opens com.azure.communication.phonenumbersdemo.models to\n com.azure.core,\n" + + " com.fasterxml.jackson.databind;\n}"; String output = PartialUpdateHandler.handlePartialUpdateForFile(generatedFileContent, existingFileContent); CompilationUnit compilationUnit = parse(output); - assertEquals(true, compilationUnit.getModule().isPresent()); - assertEquals("com.azure.communication.phonenumbersdemo", - compilationUnit.getModule().get().getName().toString()); - assertEquals(5, compilationUnit.getModule().get().getDirectives().size()); - assertEquals("requires transitive com.azure.core;", - compilationUnit.getModule() - .get() - .getDirectives() - .get(0) - .asModuleRequiresDirective() - .getTokenRange() - .get() - .toString()); - assertEquals("exports com.azure.communication.phonenumbersdemo;", - compilationUnit.getModule() - .get() - .getDirectives() - .get(1) - .asModuleExportsDirective() - .getTokenRange() - .get() - .toString()); - assertEquals("exports com.azure.communication.phonenumbersdemo.models;", - compilationUnit.getModule() - .get() - .getDirectives() - .get(2) - .asModuleExportsDirective() - .getTokenRange() - .get() - .toString()); + ModuleDeclaration module = compilationUnit.getModule().orElseThrow(); + assertEquals("com.azure.communication.phonenumbersdemo", module.getName().toString()); + assertEquals(5, module.getDirectives().size()); + assertEquals("requires transitive com.azure.core;", moduleDirectiveToString(module, 0)); + assertEquals("exports com.azure.communication.phonenumbersdemo;", moduleDirectiveToString(module, 1)); + assertEquals("exports com.azure.communication.phonenumbersdemo.models;", moduleDirectiveToString(module, 2)); assertEquals( "opens com.azure.communication.phonenumbersdemo.implementation.models to com.azure.core, com.fasterxml.jackson.databind;", - compilationUnit.getModule() - .get() - .getDirectives() - .get(3) - .asModuleOpensDirective() - .getTokenRange() - .get() - .toString()); + moduleDirectiveToString(module, 3)); assertEquals( "opens com.azure.communication.phonenumbersdemo.models to com.azure.core, com.fasterxml.jackson.databind;", - compilationUnit.getModule() - .get() - .getDirectives() - .get(4) - .asModuleOpensDirective() - .getTokenRange() - .get() - .toString()); + moduleDirectiveToString(module, 4)); } @Test public void testModuleInfoFileToTestMergeExistingFileAndGeneratedFileToTestWhenExistingAndGeneratedFileHasSameContent() { - String existingFileContent - = "module com.azure.communication.phonenumbersdemo {\n" + " requires transitive com.azure.core;\n" + "\n" - + " exports com.azure.communication.phonenumbersdemo;\n" - + " exports com.azure.communication.phonenumbersdemo.models;\n" + "\n" - + " opens com.azure.communication.phonenumbersdemo.implementation.models to\n" - + " com.azure.core,\n" + " com.fasterxml.jackson.databind;\n" - + " opens com.azure.communication.phonenumbersdemo.models to\n" + " com.azure.core,\n" - + " com.fasterxml.jackson.databind;\n" + "}"; - String generatedFileContent - = "module com.azure.communication.phonenumbersdemo {\n" + " requires transitive com.azure.core;\n" + "\n" - + " exports com.azure.communication.phonenumbersdemo;\n" - + " exports com.azure.communication.phonenumbersdemo.models;\n" + "\n" - + " opens com.azure.communication.phonenumbersdemo.implementation.models to\n" - + " com.azure.core,\n" + " com.fasterxml.jackson.databind;\n" - + " opens com.azure.communication.phonenumbersdemo.models to\n" + " com.azure.core,\n" - + " com.fasterxml.jackson.databind;\n" + "}"; + String existingFileContent = "module com.azure.communication.phonenumbersdemo {\n" + + " requires transitive com.azure.core;\n\n exports com.azure.communication.phonenumbersdemo;\n" + + " exports com.azure.communication.phonenumbersdemo.models;\n\n" + + " opens com.azure.communication.phonenumbersdemo.implementation.models to\n" + + " com.azure.core,\n com.fasterxml.jackson.databind;\n" + + " opens com.azure.communication.phonenumbersdemo.models to\n com.azure.core,\n" + + " com.fasterxml.jackson.databind;\n}"; + String generatedFileContent = "module com.azure.communication.phonenumbersdemo {\n" + + " requires transitive com.azure.core;\n\n exports com.azure.communication.phonenumbersdemo;\n" + + " exports com.azure.communication.phonenumbersdemo.models;\n\n" + + " opens com.azure.communication.phonenumbersdemo.implementation.models to\n" + + " com.azure.core,\n com.fasterxml.jackson.databind;\n" + + " opens com.azure.communication.phonenumbersdemo.models to\n com.azure.core,\n" + + " com.fasterxml.jackson.databind;\n}"; String output = PartialUpdateHandler.handlePartialUpdateForFile(generatedFileContent, existingFileContent); CompilationUnit compilationUnit = parse(output); - assertEquals(true, compilationUnit.getModule().isPresent()); - assertEquals("com.azure.communication.phonenumbersdemo", - compilationUnit.getModule().get().getName().toString()); - assertEquals(5, compilationUnit.getModule().get().getDirectives().size()); - assertEquals("requires transitive com.azure.core;", - compilationUnit.getModule() - .get() - .getDirectives() - .get(0) - .asModuleRequiresDirective() - .getTokenRange() - .get() - .toString()); - assertEquals("exports com.azure.communication.phonenumbersdemo;", - compilationUnit.getModule() - .get() - .getDirectives() - .get(1) - .asModuleExportsDirective() - .getTokenRange() - .get() - .toString()); - assertEquals("exports com.azure.communication.phonenumbersdemo.models;", - compilationUnit.getModule() - .get() - .getDirectives() - .get(2) - .asModuleExportsDirective() - .getTokenRange() - .get() - .toString()); + ModuleDeclaration module = compilationUnit.getModule().orElseThrow(); + assertEquals("com.azure.communication.phonenumbersdemo", module.getName().toString()); + assertEquals(5, module.getDirectives().size()); + assertEquals("requires transitive com.azure.core;", moduleDirectiveToString(module, 0)); + assertEquals("exports com.azure.communication.phonenumbersdemo;", moduleDirectiveToString(module, 1)); + assertEquals("exports com.azure.communication.phonenumbersdemo.models;", moduleDirectiveToString(module, 2)); assertEquals( "opens com.azure.communication.phonenumbersdemo.implementation.models to com.azure.core, com.fasterxml.jackson.databind;", - compilationUnit.getModule() - .get() - .getDirectives() - .get(3) - .asModuleOpensDirective() - .getTokenRange() - .get() - .toString()); + moduleDirectiveToString(module, 3)); assertEquals( "opens com.azure.communication.phonenumbersdemo.models to com.azure.core, com.fasterxml.jackson.databind;", - compilationUnit.getModule() - .get() - .getDirectives() - .get(4) - .asModuleOpensDirective() - .getTokenRange() - .get() - .toString()); + moduleDirectiveToString(module, 4)); } @Test public void testModuleInfoFileToTestMergeExistingFileAndGeneratedFileToTestIgnoreEmptyLineAndWhiteSpace() { String existingFileContent - = "module com.azure.communication.phonenumbersdemo {\n" + " requires transitive com.azure.core;\n" + "\n" - + "\n" + " exports com.azure.communication.phonenumbersdemo; \n" - + " exports com.azure.communication.phonenumbersdemo.models;\n" + "\n" + "}"; - String generatedFileContent - = "module com.azure.communication.phonenumbersdemo {\n" + " requires transitive com.azure.core;\n" + "\n" - + " exports com.azure.communication.phonenumbersdemo;\n" - + " exports com.azure.communication.phonenumbersdemo.models;\n" + "\n" + "}"; + = "module com.azure.communication.phonenumbersdemo {\n" + " requires transitive com.azure.core;\n\n\n" + + " exports com.azure.communication.phonenumbersdemo; \n" + + " exports com.azure.communication.phonenumbersdemo.models;\n\n}"; + String generatedFileContent = "module com.azure.communication.phonenumbersdemo {\n" + + " requires transitive com.azure.core;\n\n exports com.azure.communication.phonenumbersdemo;\n" + + " exports com.azure.communication.phonenumbersdemo.models;\n\n}"; String output = PartialUpdateHandler.handlePartialUpdateForFile(generatedFileContent, existingFileContent); CompilationUnit compilationUnit = parse(output); - assertEquals(true, compilationUnit.getModule().isPresent()); - assertEquals("com.azure.communication.phonenumbersdemo", - compilationUnit.getModule().get().getName().toString()); - assertEquals(3, compilationUnit.getModule().get().getDirectives().size()); - assertEquals("requires transitive com.azure.core;", - compilationUnit.getModule() - .get() - .getDirectives() - .get(0) - .asModuleRequiresDirective() - .getTokenRange() - .get() - .toString()); - assertEquals("exports com.azure.communication.phonenumbersdemo;", - compilationUnit.getModule() - .get() - .getDirectives() - .get(1) - .asModuleExportsDirective() - .getTokenRange() - .get() - .toString()); - assertEquals("exports com.azure.communication.phonenumbersdemo.models;", - compilationUnit.getModule() - .get() - .getDirectives() - .get(2) - .asModuleExportsDirective() - .getTokenRange() - .get() - .toString()); + ModuleDeclaration module = compilationUnit.getModule().orElseThrow(); + assertEquals("com.azure.communication.phonenumbersdemo", module.getName().toString()); + assertEquals(3, module.getDirectives().size()); + assertEquals("requires transitive com.azure.core;", moduleDirectiveToString(module, 0)); + assertEquals("exports com.azure.communication.phonenumbersdemo;", moduleDirectiveToString(module, 1)); + assertEquals("exports com.azure.communication.phonenumbersdemo.models;", moduleDirectiveToString(module, 2)); } @Test public void testStaticBlockOverride() throws Exception { - String existingFileContent = Files.readString( - Paths.get(getClass().getClassLoader().getResource("partialupdate/ModelWithStaticBlock.java").toURI())); - String generatedFileContent = Files.readString(Paths - .get(getClass().getClassLoader().getResource("partialupdate/ModelWithStaticBlockGenerated.java").toURI())); + String existingFileContent = load("partialupdate/ModelWithStaticBlock.java"); + String generatedFileContent = load("partialupdate/ModelWithStaticBlockGenerated.java"); String output = PartialUpdateHandler.handlePartialUpdateForFile(generatedFileContent, existingFileContent); CompilationUnit compilationUnit = parse(output); assertEquals(1, compilationUnit.getTypes().size()); - List staticInitializerDeclaration = compilationUnit.getTypes() + List> staticInitializerDeclaration = compilationUnit.getTypes() .get(0) .getMembers() .stream() - .filter(m -> m instanceof InitializerDeclaration) - .map(m -> (InitializerDeclaration) m) - .filter(InitializerDeclaration::isStatic) + .filter(m -> m.isInitializerDeclaration() && m.asInitializerDeclaration().isStatic()) .collect(Collectors.toList()); // verify 1 block Assertions.assertEquals(1, staticInitializerDeclaration.size()); @@ -613,25 +393,21 @@ public void testStaticBlockOverride() throws Exception { @Test public void testStaticBlockAdd() throws Exception { - String existingFileContent = Files.readString( - Paths.get(getClass().getClassLoader().getResource("partialupdate/ModelWithoutStaticBlock.java").toURI())); - String generatedFileContent = Files.readString(Paths - .get(getClass().getClassLoader().getResource("partialupdate/ModelWithStaticBlockGenerated.java").toURI())); + String existingFileContent = load("partialupdate/ModelWithoutStaticBlock.java"); + String generatedFileContent = load("partialupdate/ModelWithStaticBlockGenerated.java"); String output = PartialUpdateHandler.handlePartialUpdateForFile(generatedFileContent, existingFileContent); CompilationUnit compilationUnit = parse(output); assertEquals(1, compilationUnit.getTypes().size()); - List staticInitializerDeclaration = compilationUnit.getTypes() - .get(0) - .getMembers() - .stream() - .filter(m -> m instanceof InitializerDeclaration) - .map(m -> (InitializerDeclaration) m) - .filter(InitializerDeclaration::isStatic) - .collect(Collectors.toList()); // verify 1 block - Assertions.assertEquals(1, staticInitializerDeclaration.size()); + assertEquals(1, + compilationUnit.getTypes() + .get(0) + .getMembers() + .stream() + .filter(m -> m.isInitializerDeclaration() && m.asInitializerDeclaration().isStatic()) + .count()); // also verify a few other methods is added Assertions.assertNotNull(compilationUnit.getTypes().get(0).getMethodsByName("serializeAsJsonMergePatch")); Assertions.assertNotNull(compilationUnit.getTypes().get(0).getFieldByName("jsonMergePatch")); @@ -640,50 +416,49 @@ public void testStaticBlockAdd() throws Exception { @Test public void testStaticBlockRemove() throws Exception { - String existingFileContent = Files.readString( - Paths.get(getClass().getClassLoader().getResource("partialupdate/ModelWithStaticBlock.java").toURI())); - String generatedFileContent = Files.readString(Paths.get( - getClass().getClassLoader().getResource("partialupdate/ModelWithoutStaticBlockGenerated.java").toURI())); + String existingFileContent = load("partialupdate/ModelWithStaticBlock.java"); + String generatedFileContent = load("partialupdate/ModelWithoutStaticBlockGenerated.java"); String output = PartialUpdateHandler.handlePartialUpdateForFile(generatedFileContent, existingFileContent); CompilationUnit compilationUnit = parse(output); assertEquals(1, compilationUnit.getTypes().size()); - List staticInitializerDeclaration = compilationUnit.getTypes() + // Verify no static initialization blocks exist. + assertTrue(compilationUnit.getTypes() .get(0) .getMembers() .stream() - .filter(m -> m instanceof InitializerDeclaration) - .map(m -> (InitializerDeclaration) m) - .filter(InitializerDeclaration::isStatic) - .collect(Collectors.toList()); - // verify 0 block - Assertions.assertEquals(0, staticInitializerDeclaration.size()); + .noneMatch(m -> m.isInitializerDeclaration() && m.asInitializerDeclaration().isStatic())); } @Test public void testCodeFormatterOff() throws Exception { - String existingFileContent = Files.readString( - Paths.get(getClass().getClassLoader().getResource("partialupdate/ModelWithCodeFormatterOff.java").toURI())); - String generatedFileContent = Files.readString( - Paths.get(getClass().getClassLoader().getResource("partialupdate/GeneratedModel.java").toURI())); + String existingFileContent = load("partialupdate/ModelWithCodeFormatterOff.java"); + String generatedFileContent = load("partialupdate/GeneratedModel.java"); String output = PartialUpdateHandler.handlePartialUpdateForFile(generatedFileContent, existingFileContent); CompilationUnit compilationUnit = parse(output); ConstructorDeclaration constructorDeclaration = compilationUnit.getTypes().get(0).getConstructors().get(1); - Assertions.assertTrue( - constructorDeclaration.getJavadoc().get().getDescription().toText().contains("")); - Assertions.assertTrue( - constructorDeclaration.getJavadoc().get().getDescription().toText().contains("")); - BlockStmt constructorCodeBlock = (BlockStmt) constructorDeclaration.getChildNodes() - .stream() - .filter(node -> node instanceof BlockStmt) - .findFirst() - .get(); + + // Check that the Javadoc retained formatter flags. + String javadoc = constructorDeclaration.getJavadoc().map(doc -> doc.getDescription().toText()).orElseThrow(); + Assertions.assertTrue(javadoc.contains("")); + Assertions.assertTrue(javadoc.contains("")); + + // Check that the constructor body retained formatter flags. List lines - = Arrays.stream(constructorCodeBlock.toString().split("\n")).map(String::trim).collect(Collectors.toList()); + = constructorDeclaration.getBody().toString().lines().map(String::trim).collect(Collectors.toList()); Assertions.assertTrue(lines.contains("// @formatter:off")); Assertions.assertTrue(lines.contains("// @formatter:on")); } + + private String load(String resource) throws IOException, URISyntaxException { + URL resourceUrl = Objects.requireNonNull(getClass().getClassLoader().getResource(resource)); + return Files.readString(Paths.get(resourceUrl.toURI())); + } + + private static String moduleDirectiveToString(ModuleDeclaration module, int index) { + return module.getDirectives().get(index).getTokenRange().map(TokenRange::toString).orElseThrow(); + } } diff --git a/packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/postprocessor/implementation/CodeFormatterUtilTests.java b/packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/postprocessor/implementation/CodeFormatterUtilTests.java new file mode 100644 index 00000000000..4a7fad1c5a9 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/postprocessor/implementation/CodeFormatterUtilTests.java @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.microsoft.typespec.http.client.generator.core.postprocessor.implementation; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +public class CodeFormatterUtilTests { + @ParameterizedTest + @ValueSource(strings = { "module-info.java", "src/main/module-info.java" }) + public void moduleInfoFormatting(String fileName) { + String initial = String.join("\n", "// Copyright (c) Microsoft Corporation. All rights reserved.", + "// Licensed under the MIT License.", "// Code generated by Microsoft (R) TypeSpec Code Generator.", "", + "module com.azure.resourcemanager.avs {", "requires transitive com.azure.core.management;", + "exports com.azure.resourcemanager.avs;", "exports com.azure.resourcemanager.avs.fluent;", + "exports com.azure.resourcemanager.avs.fluent.models;", "exports com.azure.resourcemanager.avs.models;", + "opens com.azure.resourcemanager.avs.fluent.models", "to com.azure.core;", + "opens com.azure.resourcemanager.avs.models", "to com.azure.core;", + "opens com.azure.resourcemanager.avs.implementation.models to com.azure.core;", "}"); + String expected = String.join("\n", "// Copyright (c) Microsoft Corporation. All rights reserved.", + "// Licensed under the MIT License.", "// Code generated by Microsoft (R) TypeSpec Code Generator.", "", + "module com.azure.resourcemanager.avs {", " requires transitive com.azure.core.management;", "", + " exports com.azure.resourcemanager.avs;", " exports com.azure.resourcemanager.avs.fluent;", + " exports com.azure.resourcemanager.avs.fluent.models;", + " exports com.azure.resourcemanager.avs.models;", "", + " opens com.azure.resourcemanager.avs.fluent.models to com.azure.core;", + " opens com.azure.resourcemanager.avs.models to com.azure.core;", + " opens com.azure.resourcemanager.avs.implementation.models to com.azure.core;", "}", ""); + + List formattingResult = CodeFormatterUtil.formatCode(new HashMap<>(Map.of(fileName, initial))); + + assertEquals(1, formattingResult.size()); + assertEquals(expected, formattingResult.get(0)); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/util/ModelTestCaseUtilTests.java b/packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/util/ModelTestCaseUtilTests.java index 9ba2e415227..fe135218b64 100644 --- a/packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/util/ModelTestCaseUtilTests.java +++ b/packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/util/ModelTestCaseUtilTests.java @@ -20,7 +20,7 @@ public void testJsonFromEnumType() { .build(); Object jsonObject = ModelTestCaseUtil.jsonFromType(0, type); - Assertions.assertTrue(jsonObject instanceof String); + Assertions.assertInstanceOf(String.class, jsonObject); Assertions.assertTrue(Objects.equals("200", jsonObject) || Objects.equals("404", jsonObject)); type = new EnumType.Builder().elementType(ClassType.INTEGER) @@ -28,7 +28,7 @@ public void testJsonFromEnumType() { .build(); jsonObject = ModelTestCaseUtil.jsonFromType(0, type); - Assertions.assertTrue(jsonObject instanceof Integer); + Assertions.assertInstanceOf(Integer.class, jsonObject); Assertions.assertTrue(Objects.equals(200, jsonObject) || Objects.equals(404, jsonObject)); } } diff --git a/packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/util/SchemaUtilTests.java b/packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/util/SchemaUtilTests.java index e886a6c6105..f399a1e0e5d 100644 --- a/packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/util/SchemaUtilTests.java +++ b/packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/util/SchemaUtilTests.java @@ -66,17 +66,17 @@ public void testObjectSchemaFindParent() { Assertions.assertEquals(PET, SchemaUtil.getLowestCommonParent(List.of(CAT, DOG, CORGI))); ObjectSchema dummy = new ObjectSchema(); dummy.set$key("dummy"); - Assertions.assertTrue(SchemaUtil.getLowestCommonParent(List.of(dummy, DOG)) instanceof AnySchema); + Assertions.assertInstanceOf(AnySchema.class, SchemaUtil.getLowestCommonParent(List.of(dummy, DOG))); } @Test public void testAllSchemaFindParent() { - Assertions.assertTrue(SchemaUtil.getLowestCommonParent(List.of(new ArraySchema(), PET)) instanceof AnySchema); - Assertions - .assertTrue(SchemaUtil.getLowestCommonParent(List.of(new DictionarySchema(), PET)) instanceof AnySchema); + Assertions.assertInstanceOf(AnySchema.class, SchemaUtil.getLowestCommonParent(List.of(new ArraySchema(), PET))); + Assertions.assertInstanceOf(AnySchema.class, + SchemaUtil.getLowestCommonParent(List.of(new DictionarySchema(), PET))); StringSchema stringSchema = new StringSchema(); - Assertions.assertTrue(SchemaUtil.getLowestCommonParent(List.of(stringSchema)) instanceof StringSchema); - Assertions - .assertTrue(SchemaUtil.getLowestCommonParent(List.of(stringSchema, stringSchema)) instanceof StringSchema); + Assertions.assertInstanceOf(StringSchema.class, SchemaUtil.getLowestCommonParent(List.of(stringSchema))); + Assertions.assertInstanceOf(StringSchema.class, + SchemaUtil.getLowestCommonParent(List.of(stringSchema, stringSchema))); } } diff --git a/packages/http-client-java/generator/pom.xml b/packages/http-client-java/generator/pom.xml index b6a21f416cf..83b81a56d05 100644 --- a/packages/http-client-java/generator/pom.xml +++ b/packages/http-client-java/generator/pom.xml @@ -77,6 +77,14 @@ 1 false + + --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED + --add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED + --add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED + --add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED + --add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED + --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED + From f3d792b252c6f40be0e174496d9f34d453676026 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Thu, 4 Dec 2025 19:39:07 -0800 Subject: [PATCH 06/40] Add security warning to tsp init documentation and CLI for external templates (#8917) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add warning to documentation and CLI help for templateUrl parameter in tsp init command **Completed:** - [x] Explore repository structure and locate documentation files - [x] Install dependencies - [x] Add warning to CLI reference documentation (/website/src/content/docs/docs/handbook/cli.md) - [x] Add warning to scaffolding template documentation (/website/src/content/docs/docs/extending-typespec/writing-scaffolding-template.md) - [x] Add warning to templatesUrl parameter description in CLI code (packages/compiler/src/core/cli/cli.ts) - [x] Build and validate the documentation changes - [x] Address code review feedback for consistency - [x] Add changelog entry for @typespec/compiler referencing issue #8916 - [x] Review and finalize **Changes Made:** - Added security warnings to both the CLI handbook and scaffolding templates documentation - Added security warning to the templatesUrl parameter description in the CLI code, which appears in the `tsp init --help` output - The warnings inform users that downloading or using an untrusted template may contain malicious packages that can compromise their system and data, matching the warning prompt shown in the `tsp init` command - Warning text is consistent across documentation files and CLI help - Added changelog entry using chronus format for @typespec/compiler package only (no changelog needed for website documentation changes) - Fixes microsoft/typespec#8916
Original prompt > > ---- > > *This section details on the original issue you should resolve* > > Add warning text to documentation on `templateUrl` parameter in tsp init command > External templates *can* contain malicious packages and the like. We prompt about this when folks use `tsp init`: > > ```bash > warning: Downloading or using an untrusted template may contain malicious packages that can compromise your system and data. Proceed with caution and verify the source. > ? Continue (Y/n) > ``` > > We should also add a similar warning to the reference doc on tsp init > > Add a warning to the documentation on the templateUrl parameter to `tsp init`, similar to the warning prompt mentioned in the bug. It should be clear to users that using tsp init with an external templateUrl is unsafe, unless the template source is trusted. > > ## Comments on the Issue (you are @copilot in this section) > > > >
- Fixes microsoft/typespec#8916 --- ✨ Let Copilot coding agent [set things up for you](https://github.com/microsoft/typespec/issues/new?title=✨+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot) — coding agent works faster and does higher quality work when set up for your repo. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: markcowl <1054056+markcowl@users.noreply.github.com> --- ...d-security-warning-tsp-init-docs-2025-11-10-20-22-32.md | 7 +++++++ packages/compiler/src/core/cli/cli.ts | 3 ++- .../extending-typespec/writing-scaffolding-template.md | 4 ++++ website/src/content/docs/docs/handbook/cli.md | 4 ++++ 4 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 .chronus/changes/add-security-warning-tsp-init-docs-2025-11-10-20-22-32.md diff --git a/.chronus/changes/add-security-warning-tsp-init-docs-2025-11-10-20-22-32.md b/.chronus/changes/add-security-warning-tsp-init-docs-2025-11-10-20-22-32.md new file mode 100644 index 00000000000..ca7b265e5b7 --- /dev/null +++ b/.chronus/changes/add-security-warning-tsp-init-docs-2025-11-10-20-22-32.md @@ -0,0 +1,7 @@ +--- +changeKind: fix +packages: + - "@typespec/compiler" +--- + +Add security warning to tsp init CLI documentation for external templates (#8916) diff --git a/packages/compiler/src/core/cli/cli.ts b/packages/compiler/src/core/cli/cli.ts index 200b37502b8..80c85892d2d 100644 --- a/packages/compiler/src/core/cli/cli.ts +++ b/packages/compiler/src/core/cli/cli.ts @@ -211,7 +211,8 @@ async function main() { (cmd) => cmd .positional("templatesUrl", { - description: "Url of the initialization template", + description: + "Url of the initialization template. WARNING: Downloading or using an untrusted template may contain malicious packages that can compromise your system and data. Proceed with caution and verify the source.", type: "string", }) .option("template", { diff --git a/website/src/content/docs/docs/extending-typespec/writing-scaffolding-template.md b/website/src/content/docs/docs/extending-typespec/writing-scaffolding-template.md index 8a5571e5cde..8b3c68fa428 100644 --- a/website/src/content/docs/docs/extending-typespec/writing-scaffolding-template.md +++ b/website/src/content/docs/docs/extending-typespec/writing-scaffolding-template.md @@ -8,6 +8,10 @@ TypeSpec offers a scaffolding feature through the `tsp init` command. tsp init ``` +:::warning +When using `tsp init` with an external template URL, be aware that downloading or using an untrusted template may contain malicious packages that can compromise your system and data. Proceed with caution and verify the source. +::: + ## Setting a minimum TypeSpec version If your template requires a feature that was introduced in a later version of TypeSpec, you can specify this in the template. This will alert the user that the template may not function as expected and ask them to confirm if they wish to proceed. diff --git a/website/src/content/docs/docs/handbook/cli.md b/website/src/content/docs/docs/handbook/cli.md index 9e49446a7af..c68a7912be9 100644 --- a/website/src/content/docs/docs/handbook/cli.md +++ b/website/src/content/docs/docs/handbook/cli.md @@ -5,6 +5,10 @@ title: Cli usage See full usage documentation by typing `tsp --help`: +:::warning +When using `tsp init` with an external template URL, be aware that downloading or using an untrusted template may contain malicious packages that can compromise your system and data. Proceed with caution and verify the source. +::: + ```bash >tsp --help TypeSpec compiler v0.36.1 From e235fbdd34c6f7213ffcc60b1397cba12cb3097d Mon Sep 17 00:00:00 2001 From: Radhika Gupta Date: Fri, 5 Dec 2025 13:03:11 -0800 Subject: [PATCH 07/40] Multi-level discriminator handling improvements (#9119) This pull request refines the logic for handling multi-level discriminators in model constructor initialization within `ModelProvider.cs`. The changes ensure more accurate passing of discriminator parameters in complex inheritance scenarios, improving both correctness and maintainability. ### Multi-level discriminator handling improvements * Updated the logic to check whether the current model or base model uses a multi-level discriminator, ensuring the correct constructor is called and the appropriate discriminator value is passed in multi-level inheritance scenarios. * Enhanced the handling of discriminator parameters: now, when initializing constructors, the code attempts to pass through the discriminator parameter from the base model if available, otherwise falls back to using the current model's discriminator value. * Improved the logic in `GetExpressionForCtor` to correctly decide when to pass through the discriminator parameter or use the model's own discriminator value, based on whether the model is part of a multi-level discriminator hierarchy. ### Constructor initialization logic * Ensured that base constructor calls are properly made even when there are no base parameters, maintaining correct inheritance behavior. --- .../Generated/AnimalOperations.RestClient.cs | 45 + .../src/Generated/AnimalOperations.cs | 275 ++ .../src/Generated/DogOperations.RestClient.cs | 31 + .../src/Generated/DogOperations.cs | 155 + .../Generated/Models/Animal.Serialization.cs | 159 + .../src/Generated/Models/Animal.cs | 45 + .../src/Generated/Models/Dog.Serialization.cs | 162 + .../SampleClient/src/Generated/Models/Dog.cs | 40 + .../src/Generated/Models/Pet.Serialization.cs | 129 + .../SampleClient/src/Generated/Models/Pet.cs | 37 + .../Generated/Models/SampleTypeSpecContext.cs | 5 + .../Models/UnknownAnimal.Serialization.cs | 128 + .../src/Generated/Models/UnknownAnimal.cs | 20 + .../Models/UnknownPet.Serialization.cs | 134 + .../src/Generated/Models/UnknownPet.cs | 21 + .../src/Generated/PetOperations.RestClient.cs | 45 + .../src/Generated/PetOperations.cs | 275 ++ .../src/Generated/SampleTypeSpecClient.cs | 21 + .../Generated/SampleTypeSpecModelFactory.cs | 31 + .../client/csharp/SampleService/main.tsp | 68 + .../src/Providers/ModelProvider.cs | 65 +- .../ModelProviders/ModelProviderTests.cs | 69 + .../Local.Tests/HierarchyBuildingTests.cs | 223 ++ .../Generated/AnimalOperations.RestClient.cs | 48 + .../src/Generated/AnimalOperations.cs | 174 + .../src/Generated/DogOperations.RestClient.cs | 34 + .../src/Generated/DogOperations.cs | 106 + .../Generated/Models/Animal.Serialization.cs | 162 + .../src/Generated/Models/Animal.cs | 48 + .../src/Generated/Models/Dog.Serialization.cs | 165 + .../src/Generated/Models/Dog.cs | 43 + .../src/Generated/Models/Pet.Serialization.cs | 132 + .../src/Generated/Models/Pet.cs | 49 + .../Generated/Models/SampleTypeSpecContext.cs | 5 + .../Models/UnknownAnimal.Serialization.cs | 131 + .../src/Generated/Models/UnknownAnimal.cs | 23 + .../Models/UnknownPet.Serialization.cs | 137 + .../src/Generated/Models/UnknownPet.cs | 24 + .../src/Generated/PetOperations.RestClient.cs | 48 + .../src/Generated/PetOperations.cs | 174 + .../src/Generated/SampleTypeSpecClient.cs | 21 + .../Generated/SampleTypeSpecModelFactory.cs | 31 + .../Local/Sample-TypeSpec/tspCodeModel.json | 2818 ++++++++++++----- 43 files changed, 5783 insertions(+), 773 deletions(-) create mode 100644 docs/samples/client/csharp/SampleService/SampleClient/src/Generated/AnimalOperations.RestClient.cs create mode 100644 docs/samples/client/csharp/SampleService/SampleClient/src/Generated/AnimalOperations.cs create mode 100644 docs/samples/client/csharp/SampleService/SampleClient/src/Generated/DogOperations.RestClient.cs create mode 100644 docs/samples/client/csharp/SampleService/SampleClient/src/Generated/DogOperations.cs create mode 100644 docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/Animal.Serialization.cs create mode 100644 docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/Animal.cs create mode 100644 docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/Dog.Serialization.cs create mode 100644 docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/Dog.cs create mode 100644 docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/Pet.Serialization.cs create mode 100644 docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/Pet.cs create mode 100644 docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/UnknownAnimal.Serialization.cs create mode 100644 docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/UnknownAnimal.cs create mode 100644 docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/UnknownPet.Serialization.cs create mode 100644 docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/UnknownPet.cs create mode 100644 docs/samples/client/csharp/SampleService/SampleClient/src/Generated/PetOperations.RestClient.cs create mode 100644 docs/samples/client/csharp/SampleService/SampleClient/src/Generated/PetOperations.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Local.Tests/HierarchyBuildingTests.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/AnimalOperations.RestClient.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/AnimalOperations.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/DogOperations.RestClient.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/DogOperations.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/Animal.Serialization.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/Animal.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/Dog.Serialization.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/Dog.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/Pet.Serialization.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/Pet.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/UnknownAnimal.Serialization.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/UnknownAnimal.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/UnknownPet.Serialization.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/UnknownPet.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/PetOperations.RestClient.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/PetOperations.cs diff --git a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/AnimalOperations.RestClient.cs b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/AnimalOperations.RestClient.cs new file mode 100644 index 00000000000..5798e0deb91 --- /dev/null +++ b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/AnimalOperations.RestClient.cs @@ -0,0 +1,45 @@ +// + +#nullable disable + +using System.ClientModel; +using System.ClientModel.Primitives; + +namespace SampleTypeSpec +{ + /// + public partial class AnimalOperations + { + private static PipelineMessageClassifier _pipelineMessageClassifier200; + + private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 = PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); + + internal PipelineMessage CreateUpdatePetAsAnimalRequest(BinaryContent content, RequestOptions options) + { + ClientUriBuilder uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/animals/pet/as-animal", false); + PipelineMessage message = Pipeline.CreateMessage(uri.ToUri(), "PUT", PipelineMessageClassifier200); + PipelineRequest request = message.Request; + request.Headers.Set("Content-Type", "application/json"); + request.Headers.Set("Accept", "application/json"); + request.Content = content; + message.Apply(options); + return message; + } + + internal PipelineMessage CreateUpdateDogAsAnimalRequest(BinaryContent content, RequestOptions options) + { + ClientUriBuilder uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/animals/dog/as-animal", false); + PipelineMessage message = Pipeline.CreateMessage(uri.ToUri(), "PUT", PipelineMessageClassifier200); + PipelineRequest request = message.Request; + request.Headers.Set("Content-Type", "application/json"); + request.Headers.Set("Accept", "application/json"); + request.Content = content; + message.Apply(options); + return message; + } + } +} diff --git a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/AnimalOperations.cs b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/AnimalOperations.cs new file mode 100644 index 00000000000..39ba0f88e01 --- /dev/null +++ b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/AnimalOperations.cs @@ -0,0 +1,275 @@ +// + +#nullable disable + +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Threading; +using System.Threading.Tasks; + +namespace SampleTypeSpec +{ + /// The AnimalOperations sub-client. + public partial class AnimalOperations + { + private readonly Uri _endpoint; + + /// Initializes a new instance of AnimalOperations for mocking. + protected AnimalOperations() + { + } + + /// Initializes a new instance of AnimalOperations. + /// The HTTP pipeline for sending and receiving REST requests and responses. + /// Service endpoint. + internal AnimalOperations(ClientPipeline pipeline, Uri endpoint) + { + _endpoint = endpoint; + Pipeline = pipeline; + } + + /// The HTTP pipeline for sending and receiving REST requests and responses. + public ClientPipeline Pipeline { get; } + + /// + /// [Protocol Method] Update a pet as an animal + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// The content to send as the body of the request. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult UpdatePetAsAnimal(BinaryContent content, RequestOptions options = null) + { + try + { + System.Console.WriteLine("Entering method UpdatePetAsAnimal."); + Argument.AssertNotNull(content, nameof(content)); + + using PipelineMessage message = CreateUpdatePetAsAnimalRequest(content, options); + return ClientResult.FromResponse(Pipeline.ProcessMessage(message, options)); + } + catch (Exception ex) + { + System.Console.WriteLine($"An exception was thrown in method UpdatePetAsAnimal: {ex}"); + throw; + } + finally + { + System.Console.WriteLine("Exiting method UpdatePetAsAnimal."); + } + } + + /// + /// [Protocol Method] Update a pet as an animal + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// The content to send as the body of the request. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task UpdatePetAsAnimalAsync(BinaryContent content, RequestOptions options = null) + { + try + { + System.Console.WriteLine("Entering method UpdatePetAsAnimalAsync."); + Argument.AssertNotNull(content, nameof(content)); + + using PipelineMessage message = CreateUpdatePetAsAnimalRequest(content, options); + return ClientResult.FromResponse(await Pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + catch (Exception ex) + { + System.Console.WriteLine($"An exception was thrown in method UpdatePetAsAnimalAsync: {ex}"); + throw; + } + finally + { + System.Console.WriteLine("Exiting method UpdatePetAsAnimalAsync."); + } + } + + /// Update a pet as an animal. + /// + /// The cancellation token that can be used to cancel the operation. + /// is null. + /// Service returned a non-success status code. + public virtual ClientResult UpdatePetAsAnimal(Animal animal, CancellationToken cancellationToken = default) + { + try + { + System.Console.WriteLine("Entering method UpdatePetAsAnimal."); + Argument.AssertNotNull(animal, nameof(animal)); + + ClientResult result = UpdatePetAsAnimal(animal, cancellationToken.CanBeCanceled ? new RequestOptions { CancellationToken = cancellationToken } : null); + return ClientResult.FromValue((Animal)result, result.GetRawResponse()); + } + catch (Exception ex) + { + System.Console.WriteLine($"An exception was thrown in method UpdatePetAsAnimal: {ex}"); + throw; + } + finally + { + System.Console.WriteLine("Exiting method UpdatePetAsAnimal."); + } + } + + /// Update a pet as an animal. + /// + /// The cancellation token that can be used to cancel the operation. + /// is null. + /// Service returned a non-success status code. + public virtual async Task> UpdatePetAsAnimalAsync(Animal animal, CancellationToken cancellationToken = default) + { + try + { + System.Console.WriteLine("Entering method UpdatePetAsAnimalAsync."); + Argument.AssertNotNull(animal, nameof(animal)); + + ClientResult result = await UpdatePetAsAnimalAsync(animal, cancellationToken.CanBeCanceled ? new RequestOptions { CancellationToken = cancellationToken } : null).ConfigureAwait(false); + return ClientResult.FromValue((Animal)result, result.GetRawResponse()); + } + catch (Exception ex) + { + System.Console.WriteLine($"An exception was thrown in method UpdatePetAsAnimalAsync: {ex}"); + throw; + } + finally + { + System.Console.WriteLine("Exiting method UpdatePetAsAnimalAsync."); + } + } + + /// + /// [Protocol Method] Update a dog as an animal + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// The content to send as the body of the request. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult UpdateDogAsAnimal(BinaryContent content, RequestOptions options = null) + { + try + { + System.Console.WriteLine("Entering method UpdateDogAsAnimal."); + Argument.AssertNotNull(content, nameof(content)); + + using PipelineMessage message = CreateUpdateDogAsAnimalRequest(content, options); + return ClientResult.FromResponse(Pipeline.ProcessMessage(message, options)); + } + catch (Exception ex) + { + System.Console.WriteLine($"An exception was thrown in method UpdateDogAsAnimal: {ex}"); + throw; + } + finally + { + System.Console.WriteLine("Exiting method UpdateDogAsAnimal."); + } + } + + /// + /// [Protocol Method] Update a dog as an animal + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// The content to send as the body of the request. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task UpdateDogAsAnimalAsync(BinaryContent content, RequestOptions options = null) + { + try + { + System.Console.WriteLine("Entering method UpdateDogAsAnimalAsync."); + Argument.AssertNotNull(content, nameof(content)); + + using PipelineMessage message = CreateUpdateDogAsAnimalRequest(content, options); + return ClientResult.FromResponse(await Pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + catch (Exception ex) + { + System.Console.WriteLine($"An exception was thrown in method UpdateDogAsAnimalAsync: {ex}"); + throw; + } + finally + { + System.Console.WriteLine("Exiting method UpdateDogAsAnimalAsync."); + } + } + + /// Update a dog as an animal. + /// + /// The cancellation token that can be used to cancel the operation. + /// is null. + /// Service returned a non-success status code. + public virtual ClientResult UpdateDogAsAnimal(Animal animal, CancellationToken cancellationToken = default) + { + try + { + System.Console.WriteLine("Entering method UpdateDogAsAnimal."); + Argument.AssertNotNull(animal, nameof(animal)); + + ClientResult result = UpdateDogAsAnimal(animal, cancellationToken.CanBeCanceled ? new RequestOptions { CancellationToken = cancellationToken } : null); + return ClientResult.FromValue((Animal)result, result.GetRawResponse()); + } + catch (Exception ex) + { + System.Console.WriteLine($"An exception was thrown in method UpdateDogAsAnimal: {ex}"); + throw; + } + finally + { + System.Console.WriteLine("Exiting method UpdateDogAsAnimal."); + } + } + + /// Update a dog as an animal. + /// + /// The cancellation token that can be used to cancel the operation. + /// is null. + /// Service returned a non-success status code. + public virtual async Task> UpdateDogAsAnimalAsync(Animal animal, CancellationToken cancellationToken = default) + { + try + { + System.Console.WriteLine("Entering method UpdateDogAsAnimalAsync."); + Argument.AssertNotNull(animal, nameof(animal)); + + ClientResult result = await UpdateDogAsAnimalAsync(animal, cancellationToken.CanBeCanceled ? new RequestOptions { CancellationToken = cancellationToken } : null).ConfigureAwait(false); + return ClientResult.FromValue((Animal)result, result.GetRawResponse()); + } + catch (Exception ex) + { + System.Console.WriteLine($"An exception was thrown in method UpdateDogAsAnimalAsync: {ex}"); + throw; + } + finally + { + System.Console.WriteLine("Exiting method UpdateDogAsAnimalAsync."); + } + } + } +} diff --git a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/DogOperations.RestClient.cs b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/DogOperations.RestClient.cs new file mode 100644 index 00000000000..3b628c186da --- /dev/null +++ b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/DogOperations.RestClient.cs @@ -0,0 +1,31 @@ +// + +#nullable disable + +using System.ClientModel; +using System.ClientModel.Primitives; + +namespace SampleTypeSpec +{ + /// + public partial class DogOperations + { + private static PipelineMessageClassifier _pipelineMessageClassifier200; + + private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 = PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); + + internal PipelineMessage CreateUpdateDogAsDogRequest(BinaryContent content, RequestOptions options) + { + ClientUriBuilder uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/dogs/dog/as-dog", false); + PipelineMessage message = Pipeline.CreateMessage(uri.ToUri(), "PUT", PipelineMessageClassifier200); + PipelineRequest request = message.Request; + request.Headers.Set("Content-Type", "application/json"); + request.Headers.Set("Accept", "application/json"); + request.Content = content; + message.Apply(options); + return message; + } + } +} diff --git a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/DogOperations.cs b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/DogOperations.cs new file mode 100644 index 00000000000..553adb576a1 --- /dev/null +++ b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/DogOperations.cs @@ -0,0 +1,155 @@ +// + +#nullable disable + +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Threading; +using System.Threading.Tasks; + +namespace SampleTypeSpec +{ + /// The DogOperations sub-client. + public partial class DogOperations + { + private readonly Uri _endpoint; + + /// Initializes a new instance of DogOperations for mocking. + protected DogOperations() + { + } + + /// Initializes a new instance of DogOperations. + /// The HTTP pipeline for sending and receiving REST requests and responses. + /// Service endpoint. + internal DogOperations(ClientPipeline pipeline, Uri endpoint) + { + _endpoint = endpoint; + Pipeline = pipeline; + } + + /// The HTTP pipeline for sending and receiving REST requests and responses. + public ClientPipeline Pipeline { get; } + + /// + /// [Protocol Method] Update a dog as a dog + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// The content to send as the body of the request. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult UpdateDogAsDog(BinaryContent content, RequestOptions options = null) + { + try + { + System.Console.WriteLine("Entering method UpdateDogAsDog."); + Argument.AssertNotNull(content, nameof(content)); + + using PipelineMessage message = CreateUpdateDogAsDogRequest(content, options); + return ClientResult.FromResponse(Pipeline.ProcessMessage(message, options)); + } + catch (Exception ex) + { + System.Console.WriteLine($"An exception was thrown in method UpdateDogAsDog: {ex}"); + throw; + } + finally + { + System.Console.WriteLine("Exiting method UpdateDogAsDog."); + } + } + + /// + /// [Protocol Method] Update a dog as a dog + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// The content to send as the body of the request. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task UpdateDogAsDogAsync(BinaryContent content, RequestOptions options = null) + { + try + { + System.Console.WriteLine("Entering method UpdateDogAsDogAsync."); + Argument.AssertNotNull(content, nameof(content)); + + using PipelineMessage message = CreateUpdateDogAsDogRequest(content, options); + return ClientResult.FromResponse(await Pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + catch (Exception ex) + { + System.Console.WriteLine($"An exception was thrown in method UpdateDogAsDogAsync: {ex}"); + throw; + } + finally + { + System.Console.WriteLine("Exiting method UpdateDogAsDogAsync."); + } + } + + /// Update a dog as a dog. + /// + /// The cancellation token that can be used to cancel the operation. + /// is null. + /// Service returned a non-success status code. + public virtual ClientResult UpdateDogAsDog(Dog dog, CancellationToken cancellationToken = default) + { + try + { + System.Console.WriteLine("Entering method UpdateDogAsDog."); + Argument.AssertNotNull(dog, nameof(dog)); + + ClientResult result = UpdateDogAsDog(dog, cancellationToken.CanBeCanceled ? new RequestOptions { CancellationToken = cancellationToken } : null); + return ClientResult.FromValue((Dog)result, result.GetRawResponse()); + } + catch (Exception ex) + { + System.Console.WriteLine($"An exception was thrown in method UpdateDogAsDog: {ex}"); + throw; + } + finally + { + System.Console.WriteLine("Exiting method UpdateDogAsDog."); + } + } + + /// Update a dog as a dog. + /// + /// The cancellation token that can be used to cancel the operation. + /// is null. + /// Service returned a non-success status code. + public virtual async Task> UpdateDogAsDogAsync(Dog dog, CancellationToken cancellationToken = default) + { + try + { + System.Console.WriteLine("Entering method UpdateDogAsDogAsync."); + Argument.AssertNotNull(dog, nameof(dog)); + + ClientResult result = await UpdateDogAsDogAsync(dog, cancellationToken.CanBeCanceled ? new RequestOptions { CancellationToken = cancellationToken } : null).ConfigureAwait(false); + return ClientResult.FromValue((Dog)result, result.GetRawResponse()); + } + catch (Exception ex) + { + System.Console.WriteLine($"An exception was thrown in method UpdateDogAsDogAsync: {ex}"); + throw; + } + finally + { + System.Console.WriteLine("Exiting method UpdateDogAsDogAsync."); + } + } + } +} diff --git a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/Animal.Serialization.cs b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/Animal.Serialization.cs new file mode 100644 index 00000000000..4b8a05c0640 --- /dev/null +++ b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/Animal.Serialization.cs @@ -0,0 +1,159 @@ +// + +#nullable disable + +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Text.Json; + +namespace SampleTypeSpec +{ + /// + /// Base animal with discriminator + /// Please note this is the abstract base class. The derived classes available for instantiation are: and . + /// + [PersistableModelProxy(typeof(UnknownAnimal))] + public abstract partial class Animal : IJsonModel + { + /// Initializes a new instance of for deserialization. + internal Animal() + { + } + + /// The JSON writer. + /// The client options for reading and writing models. + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + writer.WriteStartObject(); + JsonModelWriteCore(writer, options); + writer.WriteEndObject(); + } + + /// The JSON writer. + /// The client options for reading and writing models. + protected virtual void JsonModelWriteCore(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(Animal)} does not support writing '{format}' format."); + } + writer.WritePropertyName("kind"u8); + writer.WriteStringValue(Kind); + writer.WritePropertyName("name"u8); + writer.WriteStringValue(Name); + if (options.Format != "W" && _additionalBinaryDataProperties != null) + { + foreach (var item in _additionalBinaryDataProperties) + { + writer.WritePropertyName(item.Key); +#if NET6_0_OR_GREATER + writer.WriteRawValue(item.Value); +#else + using (JsonDocument document = JsonDocument.Parse(item.Value)) + { + JsonSerializer.Serialize(writer, document.RootElement); + } +#endif + } + } + } + + /// The JSON reader. + /// The client options for reading and writing models. + Animal IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) => JsonModelCreateCore(ref reader, options); + + /// The JSON reader. + /// The client options for reading and writing models. + protected virtual Animal JsonModelCreateCore(ref Utf8JsonReader reader, ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(Animal)} does not support reading '{format}' format."); + } + using JsonDocument document = JsonDocument.ParseValue(ref reader); + return DeserializeAnimal(document.RootElement, options); + } + + /// The JSON element to deserialize. + /// The client options for reading and writing models. + internal static Animal DeserializeAnimal(JsonElement element, ModelReaderWriterOptions options) + { + if (element.ValueKind == JsonValueKind.Null) + { + return null; + } + if (element.TryGetProperty("kind"u8, out JsonElement discriminator)) + { + switch (discriminator.GetString()) + { + case "pet": + return Pet.DeserializePet(element, options); + case "dog": + return Dog.DeserializeDog(element, options); + } + } + return UnknownAnimal.DeserializeUnknownAnimal(element, options); + } + + /// The client options for reading and writing models. + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) => PersistableModelWriteCore(options); + + /// The client options for reading and writing models. + protected virtual BinaryData PersistableModelWriteCore(ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + switch (format) + { + case "J": + return ModelReaderWriter.Write(this, options, SampleTypeSpecContext.Default); + default: + throw new FormatException($"The model {nameof(Animal)} does not support writing '{options.Format}' format."); + } + } + + /// The data to parse. + /// The client options for reading and writing models. + Animal IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) => PersistableModelCreateCore(data, options); + + /// The data to parse. + /// The client options for reading and writing models. + protected virtual Animal PersistableModelCreateCore(BinaryData data, ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + switch (format) + { + case "J": + using (JsonDocument document = JsonDocument.Parse(data)) + { + return DeserializeAnimal(document.RootElement, options); + } + default: + throw new FormatException($"The model {nameof(Animal)} does not support reading '{options.Format}' format."); + } + } + + /// The client options for reading and writing models. + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + /// The to serialize into . + public static implicit operator BinaryContent(Animal animal) + { + if (animal == null) + { + return null; + } + return BinaryContent.Create(animal, ModelSerializationExtensions.WireOptions); + } + + /// The to deserialize the from. + public static explicit operator Animal(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeAnimal(document.RootElement, ModelSerializationExtensions.WireOptions); + } + } +} diff --git a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/Animal.cs b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/Animal.cs new file mode 100644 index 00000000000..95a223d3cac --- /dev/null +++ b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/Animal.cs @@ -0,0 +1,45 @@ +// + +#nullable disable + +using System; +using System.Collections.Generic; + +namespace SampleTypeSpec +{ + /// + /// Base animal with discriminator + /// Please note this is the abstract base class. The derived classes available for instantiation are: and . + /// + public abstract partial class Animal + { + /// Keeps track of any properties unknown to the library. + private protected readonly IDictionary _additionalBinaryDataProperties; + + /// Initializes a new instance of . + /// The kind of animal. + /// Name of the animal. + private protected Animal(string kind, string name) + { + Kind = kind; + Name = name; + } + + /// Initializes a new instance of . + /// The kind of animal. + /// Name of the animal. + /// Keeps track of any properties unknown to the library. + internal Animal(string kind, string name, IDictionary additionalBinaryDataProperties) + { + Kind = kind; + Name = name; + _additionalBinaryDataProperties = additionalBinaryDataProperties; + } + + /// The kind of animal. + internal string Kind { get; set; } + + /// Name of the animal. + public string Name { get; set; } + } +} diff --git a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/Dog.Serialization.cs b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/Dog.Serialization.cs new file mode 100644 index 00000000000..7d2e62bb48a --- /dev/null +++ b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/Dog.Serialization.cs @@ -0,0 +1,162 @@ +// + +#nullable disable + +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.Text.Json; + +namespace SampleTypeSpec +{ + /// Dog is a specific type of pet with hierarchy building. + public partial class Dog : Pet, IJsonModel + { + /// Initializes a new instance of for deserialization. + internal Dog() + { + } + + /// The JSON writer. + /// The client options for reading and writing models. + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + writer.WriteStartObject(); + JsonModelWriteCore(writer, options); + writer.WriteEndObject(); + } + + /// The JSON writer. + /// The client options for reading and writing models. + protected override void JsonModelWriteCore(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(Dog)} does not support writing '{format}' format."); + } + base.JsonModelWriteCore(writer, options); + writer.WritePropertyName("breed"u8); + writer.WriteStringValue(Breed); + } + + /// The JSON reader. + /// The client options for reading and writing models. + Dog IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) => (Dog)JsonModelCreateCore(ref reader, options); + + /// The JSON reader. + /// The client options for reading and writing models. + protected override Animal JsonModelCreateCore(ref Utf8JsonReader reader, ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(Dog)} does not support reading '{format}' format."); + } + using JsonDocument document = JsonDocument.ParseValue(ref reader); + return DeserializeDog(document.RootElement, options); + } + + /// The JSON element to deserialize. + /// The client options for reading and writing models. + internal static Dog DeserializeDog(JsonElement element, ModelReaderWriterOptions options) + { + if (element.ValueKind == JsonValueKind.Null) + { + return null; + } + string kind = "dog"; + string name = default; + IDictionary additionalBinaryDataProperties = new ChangeTrackingDictionary(); + bool trained = default; + string breed = default; + foreach (var prop in element.EnumerateObject()) + { + if (prop.NameEquals("kind"u8)) + { + kind = prop.Value.GetString(); + continue; + } + if (prop.NameEquals("name"u8)) + { + name = prop.Value.GetString(); + continue; + } + if (prop.NameEquals("trained"u8)) + { + trained = prop.Value.GetBoolean(); + continue; + } + if (prop.NameEquals("breed"u8)) + { + breed = prop.Value.GetString(); + continue; + } + if (options.Format != "W") + { + additionalBinaryDataProperties.Add(prop.Name, BinaryData.FromString(prop.Value.GetRawText())); + } + } + return new Dog(kind, name, additionalBinaryDataProperties, trained, breed); + } + + /// The client options for reading and writing models. + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) => PersistableModelWriteCore(options); + + /// The client options for reading and writing models. + protected override BinaryData PersistableModelWriteCore(ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + switch (format) + { + case "J": + return ModelReaderWriter.Write(this, options, SampleTypeSpecContext.Default); + default: + throw new FormatException($"The model {nameof(Dog)} does not support writing '{options.Format}' format."); + } + } + + /// The data to parse. + /// The client options for reading and writing models. + Dog IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) => (Dog)PersistableModelCreateCore(data, options); + + /// The data to parse. + /// The client options for reading and writing models. + protected override Animal PersistableModelCreateCore(BinaryData data, ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + switch (format) + { + case "J": + using (JsonDocument document = JsonDocument.Parse(data)) + { + return DeserializeDog(document.RootElement, options); + } + default: + throw new FormatException($"The model {nameof(Dog)} does not support reading '{options.Format}' format."); + } + } + + /// The client options for reading and writing models. + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + /// The to serialize into . + public static implicit operator BinaryContent(Dog dog) + { + if (dog == null) + { + return null; + } + return BinaryContent.Create(dog, ModelSerializationExtensions.WireOptions); + } + + /// The to deserialize the from. + public static explicit operator Dog(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeDog(document.RootElement, ModelSerializationExtensions.WireOptions); + } + } +} diff --git a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/Dog.cs b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/Dog.cs new file mode 100644 index 00000000000..29fc705738f --- /dev/null +++ b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/Dog.cs @@ -0,0 +1,40 @@ +// + +#nullable disable + +using System; +using System.Collections.Generic; + +namespace SampleTypeSpec +{ + /// Dog is a specific type of pet with hierarchy building. + public partial class Dog : Pet + { + /// Initializes a new instance of . + /// Name of the animal. + /// Whether the pet is trained. + /// The breed of the dog. + /// or is null. + public Dog(string name, bool trained, string breed) : base(name, trained) + { + Argument.AssertNotNull(name, nameof(name)); + Argument.AssertNotNull(breed, nameof(breed)); + + Breed = breed; + } + + /// Initializes a new instance of . + /// The kind of animal. + /// Name of the animal. + /// Keeps track of any properties unknown to the library. + /// Whether the pet is trained. + /// The breed of the dog. + internal Dog(string kind, string name, IDictionary additionalBinaryDataProperties, bool trained, string breed) : base(kind, name, additionalBinaryDataProperties, trained) + { + Breed = breed; + } + + /// The breed of the dog. + public string Breed { get; set; } + } +} diff --git a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/Pet.Serialization.cs b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/Pet.Serialization.cs new file mode 100644 index 00000000000..1102daad746 --- /dev/null +++ b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/Pet.Serialization.cs @@ -0,0 +1,129 @@ +// + +#nullable disable + +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Text.Json; + +namespace SampleTypeSpec +{ + /// Pet is a discriminated animal. + public partial class Pet : Animal, IJsonModel + { + /// Initializes a new instance of for deserialization. + internal Pet() + { + } + + /// The JSON writer. + /// The client options for reading and writing models. + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + writer.WriteStartObject(); + JsonModelWriteCore(writer, options); + writer.WriteEndObject(); + } + + /// The JSON writer. + /// The client options for reading and writing models. + protected override void JsonModelWriteCore(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(Pet)} does not support writing '{format}' format."); + } + base.JsonModelWriteCore(writer, options); + writer.WritePropertyName("trained"u8); + writer.WriteBooleanValue(Trained); + } + + /// The JSON reader. + /// The client options for reading and writing models. + Pet IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) => (Pet)JsonModelCreateCore(ref reader, options); + + /// The JSON reader. + /// The client options for reading and writing models. + protected override Animal JsonModelCreateCore(ref Utf8JsonReader reader, ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(Pet)} does not support reading '{format}' format."); + } + using JsonDocument document = JsonDocument.ParseValue(ref reader); + return DeserializePet(document.RootElement, options); + } + + /// The JSON element to deserialize. + /// The client options for reading and writing models. + internal static Pet DeserializePet(JsonElement element, ModelReaderWriterOptions options) + { + if (element.ValueKind == JsonValueKind.Null) + { + return null; + } + return UnknownPet.DeserializeUnknownPet(element, options); + } + + /// The client options for reading and writing models. + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) => PersistableModelWriteCore(options); + + /// The client options for reading and writing models. + protected override BinaryData PersistableModelWriteCore(ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + switch (format) + { + case "J": + return ModelReaderWriter.Write(this, options, SampleTypeSpecContext.Default); + default: + throw new FormatException($"The model {nameof(Pet)} does not support writing '{options.Format}' format."); + } + } + + /// The data to parse. + /// The client options for reading and writing models. + Pet IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) => (Pet)PersistableModelCreateCore(data, options); + + /// The data to parse. + /// The client options for reading and writing models. + protected override Animal PersistableModelCreateCore(BinaryData data, ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + switch (format) + { + case "J": + using (JsonDocument document = JsonDocument.Parse(data)) + { + return DeserializePet(document.RootElement, options); + } + default: + throw new FormatException($"The model {nameof(Pet)} does not support reading '{options.Format}' format."); + } + } + + /// The client options for reading and writing models. + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + /// The to serialize into . + public static implicit operator BinaryContent(Pet pet) + { + if (pet == null) + { + return null; + } + return BinaryContent.Create(pet, ModelSerializationExtensions.WireOptions); + } + + /// The to deserialize the from. + public static explicit operator Pet(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializePet(document.RootElement, ModelSerializationExtensions.WireOptions); + } + } +} diff --git a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/Pet.cs b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/Pet.cs new file mode 100644 index 00000000000..fd7e8130718 --- /dev/null +++ b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/Pet.cs @@ -0,0 +1,37 @@ +// + +#nullable disable + +using System; +using System.Collections.Generic; + +namespace SampleTypeSpec +{ + /// Pet is a discriminated animal. + public partial class Pet : Animal + { + /// Initializes a new instance of . + /// Name of the animal. + /// Whether the pet is trained. + /// is null. + public Pet(string name, bool trained) : base("pet", name) + { + Argument.AssertNotNull(name, nameof(name)); + + Trained = trained; + } + + /// Initializes a new instance of . + /// The kind of animal. + /// Name of the animal. + /// Keeps track of any properties unknown to the library. + /// Whether the pet is trained. + internal Pet(string kind, string name, IDictionary additionalBinaryDataProperties, bool trained) : base(kind, name, additionalBinaryDataProperties) + { + Trained = trained; + } + + /// Whether the pet is trained. + public bool Trained { get; set; } + } +} diff --git a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/SampleTypeSpecContext.cs b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/SampleTypeSpecContext.cs index ca0a9f6991a..acbd82d2f33 100644 --- a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/SampleTypeSpecContext.cs +++ b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/SampleTypeSpecContext.cs @@ -10,7 +10,9 @@ namespace SampleTypeSpec /// Context class which will be filled in by the System.ClientModel.SourceGeneration. /// For more information /// + [ModelReaderWriterBuildable(typeof(Animal))] [ModelReaderWriterBuildable(typeof(AnotherDynamicModel))] + [ModelReaderWriterBuildable(typeof(Dog))] [ModelReaderWriterBuildable(typeof(DynamicModel))] [ModelReaderWriterBuildable(typeof(Friend))] [ModelReaderWriterBuildable(typeof(GetWidgetMetricsResponse))] @@ -21,10 +23,13 @@ namespace SampleTypeSpec [ModelReaderWriterBuildable(typeof(ModelWithEmbeddedNonBodyParameters))] [ModelReaderWriterBuildable(typeof(ModelWithRequiredNullableProperties))] [ModelReaderWriterBuildable(typeof(PageThing))] + [ModelReaderWriterBuildable(typeof(Pet))] [ModelReaderWriterBuildable(typeof(RenamedModel))] [ModelReaderWriterBuildable(typeof(ReturnsAnonymousModelResponse))] [ModelReaderWriterBuildable(typeof(RoundTripModel))] [ModelReaderWriterBuildable(typeof(Thing))] + [ModelReaderWriterBuildable(typeof(UnknownAnimal))] + [ModelReaderWriterBuildable(typeof(UnknownPet))] public partial class SampleTypeSpecContext : ModelReaderWriterContext { } diff --git a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/UnknownAnimal.Serialization.cs b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/UnknownAnimal.Serialization.cs new file mode 100644 index 00000000000..e00de335fb2 --- /dev/null +++ b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/UnknownAnimal.Serialization.cs @@ -0,0 +1,128 @@ +// + +#nullable disable + +using System; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.Text.Json; + +namespace SampleTypeSpec +{ + internal partial class UnknownAnimal : Animal, IJsonModel + { + /// Initializes a new instance of for deserialization. + internal UnknownAnimal() + { + } + + /// The JSON writer. + /// The client options for reading and writing models. + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + writer.WriteStartObject(); + JsonModelWriteCore(writer, options); + writer.WriteEndObject(); + } + + /// The JSON writer. + /// The client options for reading and writing models. + protected override void JsonModelWriteCore(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(Animal)} does not support writing '{format}' format."); + } + base.JsonModelWriteCore(writer, options); + } + + /// The JSON reader. + /// The client options for reading and writing models. + Animal IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) => JsonModelCreateCore(ref reader, options); + + /// The JSON reader. + /// The client options for reading and writing models. + protected override Animal JsonModelCreateCore(ref Utf8JsonReader reader, ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(Animal)} does not support reading '{format}' format."); + } + using JsonDocument document = JsonDocument.ParseValue(ref reader); + return DeserializeAnimal(document.RootElement, options); + } + + /// The JSON element to deserialize. + /// The client options for reading and writing models. + internal static UnknownAnimal DeserializeUnknownAnimal(JsonElement element, ModelReaderWriterOptions options) + { + if (element.ValueKind == JsonValueKind.Null) + { + return null; + } + string kind = "unknown"; + string name = default; + IDictionary additionalBinaryDataProperties = new ChangeTrackingDictionary(); + foreach (var prop in element.EnumerateObject()) + { + if (prop.NameEquals("kind"u8)) + { + kind = prop.Value.GetString(); + continue; + } + if (prop.NameEquals("name"u8)) + { + name = prop.Value.GetString(); + continue; + } + if (options.Format != "W") + { + additionalBinaryDataProperties.Add(prop.Name, BinaryData.FromString(prop.Value.GetRawText())); + } + } + return new UnknownAnimal(kind, name, additionalBinaryDataProperties); + } + + /// The client options for reading and writing models. + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) => PersistableModelWriteCore(options); + + /// The client options for reading and writing models. + protected override BinaryData PersistableModelWriteCore(ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + switch (format) + { + case "J": + return ModelReaderWriter.Write(this, options, SampleTypeSpecContext.Default); + default: + throw new FormatException($"The model {nameof(Animal)} does not support writing '{options.Format}' format."); + } + } + + /// The data to parse. + /// The client options for reading and writing models. + Animal IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) => PersistableModelCreateCore(data, options); + + /// The data to parse. + /// The client options for reading and writing models. + protected override Animal PersistableModelCreateCore(BinaryData data, ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + switch (format) + { + case "J": + using (JsonDocument document = JsonDocument.Parse(data)) + { + return DeserializeAnimal(document.RootElement, options); + } + default: + throw new FormatException($"The model {nameof(Animal)} does not support reading '{options.Format}' format."); + } + } + + /// The client options for reading and writing models. + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + } +} diff --git a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/UnknownAnimal.cs b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/UnknownAnimal.cs new file mode 100644 index 00000000000..6b283549666 --- /dev/null +++ b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/UnknownAnimal.cs @@ -0,0 +1,20 @@ +// + +#nullable disable + +using System; +using System.Collections.Generic; + +namespace SampleTypeSpec +{ + internal partial class UnknownAnimal : Animal + { + /// Initializes a new instance of . + /// The kind of animal. + /// Name of the animal. + /// Keeps track of any properties unknown to the library. + internal UnknownAnimal(string kind, string name, IDictionary additionalBinaryDataProperties) : base(kind ?? "unknown", name, additionalBinaryDataProperties) + { + } + } +} diff --git a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/UnknownPet.Serialization.cs b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/UnknownPet.Serialization.cs new file mode 100644 index 00000000000..59f22d181dc --- /dev/null +++ b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/UnknownPet.Serialization.cs @@ -0,0 +1,134 @@ +// + +#nullable disable + +using System; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.Text.Json; + +namespace SampleTypeSpec +{ + internal partial class UnknownPet : Pet, IJsonModel + { + /// Initializes a new instance of for deserialization. + internal UnknownPet() + { + } + + /// The JSON writer. + /// The client options for reading and writing models. + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + writer.WriteStartObject(); + JsonModelWriteCore(writer, options); + writer.WriteEndObject(); + } + + /// The JSON writer. + /// The client options for reading and writing models. + protected override void JsonModelWriteCore(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(Pet)} does not support writing '{format}' format."); + } + base.JsonModelWriteCore(writer, options); + } + + /// The JSON reader. + /// The client options for reading and writing models. + Pet IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) => (UnknownPet)JsonModelCreateCore(ref reader, options); + + /// The JSON reader. + /// The client options for reading and writing models. + protected override Animal JsonModelCreateCore(ref Utf8JsonReader reader, ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(Pet)} does not support reading '{format}' format."); + } + using JsonDocument document = JsonDocument.ParseValue(ref reader); + return DeserializePet(document.RootElement, options); + } + + /// The JSON element to deserialize. + /// The client options for reading and writing models. + internal static UnknownPet DeserializeUnknownPet(JsonElement element, ModelReaderWriterOptions options) + { + if (element.ValueKind == JsonValueKind.Null) + { + return null; + } + string kind = "unknown"; + string name = default; + IDictionary additionalBinaryDataProperties = new ChangeTrackingDictionary(); + bool trained = default; + foreach (var prop in element.EnumerateObject()) + { + if (prop.NameEquals("kind"u8)) + { + kind = prop.Value.GetString(); + continue; + } + if (prop.NameEquals("name"u8)) + { + name = prop.Value.GetString(); + continue; + } + if (prop.NameEquals("trained"u8)) + { + trained = prop.Value.GetBoolean(); + continue; + } + if (options.Format != "W") + { + additionalBinaryDataProperties.Add(prop.Name, BinaryData.FromString(prop.Value.GetRawText())); + } + } + return new UnknownPet(kind, name, additionalBinaryDataProperties, trained); + } + + /// The client options for reading and writing models. + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) => PersistableModelWriteCore(options); + + /// The client options for reading and writing models. + protected override BinaryData PersistableModelWriteCore(ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + switch (format) + { + case "J": + return ModelReaderWriter.Write(this, options, SampleTypeSpecContext.Default); + default: + throw new FormatException($"The model {nameof(Pet)} does not support writing '{options.Format}' format."); + } + } + + /// The data to parse. + /// The client options for reading and writing models. + Pet IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) => (UnknownPet)PersistableModelCreateCore(data, options); + + /// The data to parse. + /// The client options for reading and writing models. + protected override Animal PersistableModelCreateCore(BinaryData data, ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + switch (format) + { + case "J": + using (JsonDocument document = JsonDocument.Parse(data)) + { + return DeserializePet(document.RootElement, options); + } + default: + throw new FormatException($"The model {nameof(Pet)} does not support reading '{options.Format}' format."); + } + } + + /// The client options for reading and writing models. + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + } +} diff --git a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/UnknownPet.cs b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/UnknownPet.cs new file mode 100644 index 00000000000..d0cd927230b --- /dev/null +++ b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/UnknownPet.cs @@ -0,0 +1,21 @@ +// + +#nullable disable + +using System; +using System.Collections.Generic; + +namespace SampleTypeSpec +{ + internal partial class UnknownPet : Pet + { + /// Initializes a new instance of . + /// The kind of animal. + /// Name of the animal. + /// Keeps track of any properties unknown to the library. + /// Whether the pet is trained. + internal UnknownPet(string kind, string name, IDictionary additionalBinaryDataProperties, bool trained) : base(kind ?? "unknown", name, additionalBinaryDataProperties, trained) + { + } + } +} diff --git a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/PetOperations.RestClient.cs b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/PetOperations.RestClient.cs new file mode 100644 index 00000000000..e39efd2c1cf --- /dev/null +++ b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/PetOperations.RestClient.cs @@ -0,0 +1,45 @@ +// + +#nullable disable + +using System.ClientModel; +using System.ClientModel.Primitives; + +namespace SampleTypeSpec +{ + /// + public partial class PetOperations + { + private static PipelineMessageClassifier _pipelineMessageClassifier200; + + private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 = PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); + + internal PipelineMessage CreateUpdatePetAsPetRequest(BinaryContent content, RequestOptions options) + { + ClientUriBuilder uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/pets/pet/as-pet", false); + PipelineMessage message = Pipeline.CreateMessage(uri.ToUri(), "PUT", PipelineMessageClassifier200); + PipelineRequest request = message.Request; + request.Headers.Set("Content-Type", "application/json"); + request.Headers.Set("Accept", "application/json"); + request.Content = content; + message.Apply(options); + return message; + } + + internal PipelineMessage CreateUpdateDogAsPetRequest(BinaryContent content, RequestOptions options) + { + ClientUriBuilder uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/pets/dog/as-pet", false); + PipelineMessage message = Pipeline.CreateMessage(uri.ToUri(), "PUT", PipelineMessageClassifier200); + PipelineRequest request = message.Request; + request.Headers.Set("Content-Type", "application/json"); + request.Headers.Set("Accept", "application/json"); + request.Content = content; + message.Apply(options); + return message; + } + } +} diff --git a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/PetOperations.cs b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/PetOperations.cs new file mode 100644 index 00000000000..2a60348d6b5 --- /dev/null +++ b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/PetOperations.cs @@ -0,0 +1,275 @@ +// + +#nullable disable + +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Threading; +using System.Threading.Tasks; + +namespace SampleTypeSpec +{ + /// The PetOperations sub-client. + public partial class PetOperations + { + private readonly Uri _endpoint; + + /// Initializes a new instance of PetOperations for mocking. + protected PetOperations() + { + } + + /// Initializes a new instance of PetOperations. + /// The HTTP pipeline for sending and receiving REST requests and responses. + /// Service endpoint. + internal PetOperations(ClientPipeline pipeline, Uri endpoint) + { + _endpoint = endpoint; + Pipeline = pipeline; + } + + /// The HTTP pipeline for sending and receiving REST requests and responses. + public ClientPipeline Pipeline { get; } + + /// + /// [Protocol Method] Update a pet as a pet + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// The content to send as the body of the request. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult UpdatePetAsPet(BinaryContent content, RequestOptions options = null) + { + try + { + System.Console.WriteLine("Entering method UpdatePetAsPet."); + Argument.AssertNotNull(content, nameof(content)); + + using PipelineMessage message = CreateUpdatePetAsPetRequest(content, options); + return ClientResult.FromResponse(Pipeline.ProcessMessage(message, options)); + } + catch (Exception ex) + { + System.Console.WriteLine($"An exception was thrown in method UpdatePetAsPet: {ex}"); + throw; + } + finally + { + System.Console.WriteLine("Exiting method UpdatePetAsPet."); + } + } + + /// + /// [Protocol Method] Update a pet as a pet + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// The content to send as the body of the request. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task UpdatePetAsPetAsync(BinaryContent content, RequestOptions options = null) + { + try + { + System.Console.WriteLine("Entering method UpdatePetAsPetAsync."); + Argument.AssertNotNull(content, nameof(content)); + + using PipelineMessage message = CreateUpdatePetAsPetRequest(content, options); + return ClientResult.FromResponse(await Pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + catch (Exception ex) + { + System.Console.WriteLine($"An exception was thrown in method UpdatePetAsPetAsync: {ex}"); + throw; + } + finally + { + System.Console.WriteLine("Exiting method UpdatePetAsPetAsync."); + } + } + + /// Update a pet as a pet. + /// + /// The cancellation token that can be used to cancel the operation. + /// is null. + /// Service returned a non-success status code. + public virtual ClientResult UpdatePetAsPet(Pet pet, CancellationToken cancellationToken = default) + { + try + { + System.Console.WriteLine("Entering method UpdatePetAsPet."); + Argument.AssertNotNull(pet, nameof(pet)); + + ClientResult result = UpdatePetAsPet(pet, cancellationToken.CanBeCanceled ? new RequestOptions { CancellationToken = cancellationToken } : null); + return ClientResult.FromValue((Pet)result, result.GetRawResponse()); + } + catch (Exception ex) + { + System.Console.WriteLine($"An exception was thrown in method UpdatePetAsPet: {ex}"); + throw; + } + finally + { + System.Console.WriteLine("Exiting method UpdatePetAsPet."); + } + } + + /// Update a pet as a pet. + /// + /// The cancellation token that can be used to cancel the operation. + /// is null. + /// Service returned a non-success status code. + public virtual async Task> UpdatePetAsPetAsync(Pet pet, CancellationToken cancellationToken = default) + { + try + { + System.Console.WriteLine("Entering method UpdatePetAsPetAsync."); + Argument.AssertNotNull(pet, nameof(pet)); + + ClientResult result = await UpdatePetAsPetAsync(pet, cancellationToken.CanBeCanceled ? new RequestOptions { CancellationToken = cancellationToken } : null).ConfigureAwait(false); + return ClientResult.FromValue((Pet)result, result.GetRawResponse()); + } + catch (Exception ex) + { + System.Console.WriteLine($"An exception was thrown in method UpdatePetAsPetAsync: {ex}"); + throw; + } + finally + { + System.Console.WriteLine("Exiting method UpdatePetAsPetAsync."); + } + } + + /// + /// [Protocol Method] Update a dog as a pet + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// The content to send as the body of the request. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult UpdateDogAsPet(BinaryContent content, RequestOptions options = null) + { + try + { + System.Console.WriteLine("Entering method UpdateDogAsPet."); + Argument.AssertNotNull(content, nameof(content)); + + using PipelineMessage message = CreateUpdateDogAsPetRequest(content, options); + return ClientResult.FromResponse(Pipeline.ProcessMessage(message, options)); + } + catch (Exception ex) + { + System.Console.WriteLine($"An exception was thrown in method UpdateDogAsPet: {ex}"); + throw; + } + finally + { + System.Console.WriteLine("Exiting method UpdateDogAsPet."); + } + } + + /// + /// [Protocol Method] Update a dog as a pet + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// The content to send as the body of the request. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task UpdateDogAsPetAsync(BinaryContent content, RequestOptions options = null) + { + try + { + System.Console.WriteLine("Entering method UpdateDogAsPetAsync."); + Argument.AssertNotNull(content, nameof(content)); + + using PipelineMessage message = CreateUpdateDogAsPetRequest(content, options); + return ClientResult.FromResponse(await Pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + catch (Exception ex) + { + System.Console.WriteLine($"An exception was thrown in method UpdateDogAsPetAsync: {ex}"); + throw; + } + finally + { + System.Console.WriteLine("Exiting method UpdateDogAsPetAsync."); + } + } + + /// Update a dog as a pet. + /// + /// The cancellation token that can be used to cancel the operation. + /// is null. + /// Service returned a non-success status code. + public virtual ClientResult UpdateDogAsPet(Pet pet, CancellationToken cancellationToken = default) + { + try + { + System.Console.WriteLine("Entering method UpdateDogAsPet."); + Argument.AssertNotNull(pet, nameof(pet)); + + ClientResult result = UpdateDogAsPet(pet, cancellationToken.CanBeCanceled ? new RequestOptions { CancellationToken = cancellationToken } : null); + return ClientResult.FromValue((Pet)result, result.GetRawResponse()); + } + catch (Exception ex) + { + System.Console.WriteLine($"An exception was thrown in method UpdateDogAsPet: {ex}"); + throw; + } + finally + { + System.Console.WriteLine("Exiting method UpdateDogAsPet."); + } + } + + /// Update a dog as a pet. + /// + /// The cancellation token that can be used to cancel the operation. + /// is null. + /// Service returned a non-success status code. + public virtual async Task> UpdateDogAsPetAsync(Pet pet, CancellationToken cancellationToken = default) + { + try + { + System.Console.WriteLine("Entering method UpdateDogAsPetAsync."); + Argument.AssertNotNull(pet, nameof(pet)); + + ClientResult result = await UpdateDogAsPetAsync(pet, cancellationToken.CanBeCanceled ? new RequestOptions { CancellationToken = cancellationToken } : null).ConfigureAwait(false); + return ClientResult.FromValue((Pet)result, result.GetRawResponse()); + } + catch (Exception ex) + { + System.Console.WriteLine($"An exception was thrown in method UpdateDogAsPetAsync: {ex}"); + throw; + } + finally + { + System.Console.WriteLine("Exiting method UpdateDogAsPetAsync."); + } + } + } +} diff --git a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/SampleTypeSpecClient.cs b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/SampleTypeSpecClient.cs index 243a0d06d09..812e2900259 100644 --- a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/SampleTypeSpecClient.cs +++ b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/SampleTypeSpecClient.cs @@ -32,6 +32,9 @@ public partial class SampleTypeSpecClient } }; private readonly string _apiVersion; + private AnimalOperations _cachedAnimalOperations; + private PetOperations _cachedPetOperations; + private DogOperations _cachedDogOperations; private Metrics _cachedMetrics; /// Initializes a new instance of SampleTypeSpecClient for mocking. @@ -3008,6 +3011,24 @@ public virtual async Task DynamicModelOperationAsync(DynamicModel } } + /// Initializes a new instance of AnimalOperations. + public virtual AnimalOperations GetAnimalOperationsClient() + { + return Volatile.Read(ref _cachedAnimalOperations) ?? Interlocked.CompareExchange(ref _cachedAnimalOperations, new AnimalOperations(Pipeline, _endpoint), null) ?? _cachedAnimalOperations; + } + + /// Initializes a new instance of PetOperations. + public virtual PetOperations GetPetOperationsClient() + { + return Volatile.Read(ref _cachedPetOperations) ?? Interlocked.CompareExchange(ref _cachedPetOperations, new PetOperations(Pipeline, _endpoint), null) ?? _cachedPetOperations; + } + + /// Initializes a new instance of DogOperations. + public virtual DogOperations GetDogOperationsClient() + { + return Volatile.Read(ref _cachedDogOperations) ?? Interlocked.CompareExchange(ref _cachedDogOperations, new DogOperations(Pipeline, _endpoint), null) ?? _cachedDogOperations; + } + /// Initializes a new instance of Metrics. public virtual Metrics GetMetricsClient() { diff --git a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/SampleTypeSpecModelFactory.cs b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/SampleTypeSpecModelFactory.cs index 2d1f276ad6d..370465cb29d 100644 --- a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/SampleTypeSpecModelFactory.cs +++ b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/SampleTypeSpecModelFactory.cs @@ -230,6 +230,37 @@ public static AnotherDynamicModel AnotherDynamicModel(string bar = default) return new AnotherDynamicModel(bar, additionalBinaryDataProperties: null); } + /// + /// Base animal with discriminator + /// Please note this is the abstract base class. The derived classes available for instantiation are: and . + /// + /// The kind of animal. + /// Name of the animal. + /// A new instance for mocking. + public static Animal Animal(string kind = default, string name = default) + { + return new UnknownAnimal(kind, name, additionalBinaryDataProperties: null); + } + + /// Pet is a discriminated animal. + /// Name of the animal. + /// Whether the pet is trained. + /// A new instance for mocking. + public static Pet Pet(string name = default, bool trained = default) + { + return new Pet("pet", name, additionalBinaryDataProperties: null, trained); + } + + /// Dog is a specific type of pet with hierarchy building. + /// Name of the animal. + /// Whether the pet is trained. + /// The breed of the dog. + /// A new instance for mocking. + public static Dog Dog(string name = default, bool trained = default, string breed = default) + { + return new Dog("pet", name, additionalBinaryDataProperties: null, trained, breed); + } + /// The GetWidgetMetricsResponse. /// /// diff --git a/docs/samples/client/csharp/SampleService/main.tsp b/docs/samples/client/csharp/SampleService/main.tsp index 6352a85e816..3a6a1e6e254 100644 --- a/docs/samples/client/csharp/SampleService/main.tsp +++ b/docs/samples/client/csharp/SampleService/main.tsp @@ -502,6 +502,74 @@ op EmbeddedParameters(@bodyRoot body: ModelWithEmbeddedNonBodyParameters): void; @post op DynamicModelOperation(@body body: DynamicModel): void; +@doc("Base animal with discriminator") +@discriminator("kind") +model Animal { + @doc("The kind of animal") + kind: string; + + @doc("Name of the animal") + name: string; +} + +alias PetContent = { + @doc("Whether the pet is trained") + trained: boolean; +}; + +@doc("Pet is a discriminated animal") +model Pet extends Animal { + kind: "pet"; + ...PetContent; +} + +alias DogContent = { + @doc("The breed of the dog") + breed: string; +}; + +@doc("Dog is a specific type of pet with hierarchy building") +@Legacy.hierarchyBuilding(Pet) +model Dog extends Animal { + kind: "dog"; + ...PetContent; + ...DogContent; +} + +@route("/animals") +interface AnimalOperations { + @doc("Update a pet as an animal") + @put + @route("/pet/as-animal") + updatePetAsAnimal(@body animal: Animal): Animal; + + @doc("Update a dog as an animal") + @put + @route("/dog/as-animal") + updateDogAsAnimal(@body animal: Animal): Animal; +} + +@route("/pets") +interface PetOperations { + @doc("Update a pet as a pet") + @put + @route("/pet/as-pet") + updatePetAsPet(@body pet: Pet): Pet; + + @doc("Update a dog as a pet") + @put + @route("/dog/as-pet") + updateDogAsPet(@body pet: Pet): Pet; +} + +@route("/dogs") +interface DogOperations { + @doc("Update a dog as a dog") + @put + @route("/dog/as-dog") + updateDogAsDog(@body dog: Dog): Dog; +} + @clientInitialization({ initializedBy: InitializedBy.individually | InitializedBy.parent, }) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs index fb1b490741d..b126b0338ad 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs @@ -62,6 +62,7 @@ protected override FormattableString BuildDescription() private ModelProvider? _baseModelProvider; private ConstructorProvider? _fullConstructor; internal PropertyProvider? DiscriminatorProperty { get; private set; } + private ValueExpression DiscriminatorLiteral => Literal(_inputModel.DiscriminatorValue ?? ""); public ModelProvider(InputModelType inputModel) : base(inputModel) { @@ -723,21 +724,43 @@ private IEnumerable GetAllBaseFieldsForConstructorInitialization( AddInitializationParameterForCtor(baseParameters, Type.IsStruct, isInitializationConstructor, field: field); } + // Build constructor parameters first so we can use them for initializer + foreach (var property in CanonicalView.Properties) + { + AddInitializationParameterForCtor(constructorParameters, Type.IsStruct, isInitializationConstructor, property); + } + + foreach (var field in CanonicalView.Fields) + { + AddInitializationParameterForCtor(constructorParameters, Type.IsStruct, isInitializationConstructor, field: field); + } + + constructorParameters.InsertRange(0, _inputModel.IsUnknownDiscriminatorModel + ? baseParameters + : baseParameters.Where(p => + p.Property is null + || (!overriddenProperties.Contains(p.Property!) && (!p.Property.IsDiscriminator || !isInitializationConstructor || (includeDiscriminatorParameter && _isMultiLevelDiscriminator))))); + // construct the initializer using the parameters from base signature ConstructorInitializer? constructorInitializer = null; if (BaseModelProvider != null) { if (baseParameters.Count > 0) { - // Check if base model has dual constructor pattern and we should call private protected constructor - if (isInitializationConstructor && BaseModelProvider._isMultiLevelDiscriminator) + // Check if we should call multi-level discriminator constructor + if (isInitializationConstructor && (_isMultiLevelDiscriminator || BaseModelProvider._isMultiLevelDiscriminator)) { - // Call base model's private protected constructor with discriminator value - var args = new List(); - args.Add(Literal(_inputModel.DiscriminatorValue)); - var filteredParams = baseParameters.Where(p => p.Property is null || !p.Property.IsDiscriminator).ToList(); - args.AddRange(filteredParams.Select(p => GetExpressionForCtor(p, overriddenProperties, isInitializationConstructor))); - constructorInitializer = new ConstructorInitializer(true, args); + var baseDiscriminatorParam = baseParameters.FirstOrDefault(p => p.Property?.IsDiscriminator == true); + var hasDiscriminatorProperty = BaseModelProvider.CanonicalView.Properties.Any(p => p.IsDiscriminator); + + ValueExpression discriminatorExpression = (hasDiscriminatorProperty && baseDiscriminatorParam is not null && includeDiscriminatorParameter) + ? constructorParameters.FirstOrDefault(p => p.Property?.IsDiscriminator == true) ?? baseDiscriminatorParam + : DiscriminatorLiteral; + + var args = baseParameters.Where(p => p.Property?.IsDiscriminator != true) + .Select(p => GetExpressionForCtor(p, overriddenProperties, isInitializationConstructor)); + + constructorInitializer = new ConstructorInitializer(true, [discriminatorExpression, .. args]); } else { @@ -752,22 +775,6 @@ private IEnumerable GetAllBaseFieldsForConstructorInitialization( } } - foreach (var property in CanonicalView.Properties) - { - AddInitializationParameterForCtor(constructorParameters, Type.IsStruct, isInitializationConstructor, property); - } - - foreach (var field in CanonicalView.Fields) - { - AddInitializationParameterForCtor(constructorParameters, Type.IsStruct, isInitializationConstructor, field: field); - } - - constructorParameters.InsertRange(0, _inputModel.IsUnknownDiscriminatorModel - ? baseParameters - : baseParameters.Where(p => - p.Property is null - || (!overriddenProperties.Contains(p.Property!) && (!p.Property.IsDiscriminator || !isInitializationConstructor || includeDiscriminatorParameter)))); - if (!isInitializationConstructor) { foreach (var property in AdditionalPropertyProperties) @@ -830,7 +837,7 @@ p.Property is null } // fallback to the default value - return Literal(_inputModel.DiscriminatorValue); + return DiscriminatorLiteral; } } return null; @@ -848,6 +855,10 @@ private ValueExpression GetExpressionForCtor(ParameterProvider parameter, HashSe { return GetUnknownDiscriminatorExpression(parameter.Property) ?? throw new InvalidOperationException($"invalid discriminator {_inputModel.DiscriminatorValue} for property {parameter.Property.Name}"); } + else + { + return parameter; + } } var paramToUse = parameter.Property is not null && overriddenProperties.Contains(parameter.Property) ? Properties.First(p => p.Name == parameter.Property.Name).AsParameter : parameter; @@ -870,7 +881,7 @@ private ValueExpression GetExpressionForCtor(ParameterProvider parameter, HashSe if (type.IsStruct) { /* kind != default ? kind : "unknown" */ - return new TernaryConditionalExpression(discriminatorExpression.NotEqual(Default), discriminatorExpression, Literal(_inputModel.DiscriminatorValue)); + return new TernaryConditionalExpression(discriminatorExpression.NotEqual(Default), discriminatorExpression, DiscriminatorLiteral); } else { @@ -880,7 +891,7 @@ private ValueExpression GetExpressionForCtor(ParameterProvider parameter, HashSe else { /* kind ?? "unknown" */ - return discriminatorExpression.NullCoalesce(Literal(_inputModel.DiscriminatorValue)); + return discriminatorExpression.NullCoalesce(DiscriminatorLiteral); } } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelProviderTests.cs index 234654be7eb..b23436d0002 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelProviderTests.cs @@ -1542,5 +1542,74 @@ public void TestMultiLayerDiscriminator_ThreeLayers() Assert.AreEqual("name", catProtectedParams[2].Name); Assert.AreEqual("meows", catProtectedParams[3].Name); } + + [Test] + public void TestMultiLevelDiscriminatorConstructorParameterPassthrough() + { + // Create a three-level discriminator hierarchy: base → intermediate → derived + var derivedInputModel = InputFactory.Model( + "derived", + discriminatedKind: "derived", + properties: [ + InputFactory.Property("kind", InputPrimitiveType.String, isRequired: true, isDiscriminator: true), + InputFactory.Property("derivedProperty", InputPrimitiveType.String, isRequired: true) + ]); + + var intermediateInputModel = InputFactory.Model( + "intermediate", + discriminatedKind: "intermediate", + properties: [ + InputFactory.Property("kind", InputPrimitiveType.String, isRequired: true, isDiscriminator: true), + InputFactory.Property("intermediateProperty", InputPrimitiveType.Boolean, isRequired: true) + ], + discriminatedModels: new Dictionary() { { "derived", derivedInputModel } }); + + var baseInputModel = InputFactory.Model( + "base", + properties: [ + InputFactory.Property("kind", InputPrimitiveType.String, isRequired: true, isDiscriminator: true), + InputFactory.Property("baseProperty", InputPrimitiveType.String, isRequired: true) + ], + discriminatedModels: new Dictionary() { { "intermediate", intermediateInputModel } }); + + MockHelpers.LoadMockGenerator(inputModelTypes: [baseInputModel, intermediateInputModel, derivedInputModel]); + + var intermediateProvider = new ModelProvider(intermediateInputModel); + var derivedProvider = new ModelProvider(derivedInputModel); + + Assert.IsNotNull(intermediateProvider); + Assert.IsNotNull(derivedProvider); + + // Verify intermediate model has expected constructor count + Assert.AreEqual(3, intermediateProvider.Constructors.Count); + + // Get the protected constructor for intermediate model + var intermediateProtectedCtor = intermediateProvider.Constructors.FirstOrDefault(c => + c.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Private) && + c.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Protected)); + + Assert.IsNotNull(intermediateProtectedCtor, "Intermediate model should have a protected constructor for multi-level discriminator"); + + // Verify the base constructor call uses the discriminator parameter, not hardcoded literal + var initializer = intermediateProtectedCtor!.Signature.Initializer; + Assert.IsNotNull(initializer, "Protected constructor should have base initializer"); + Assert.IsTrue(initializer!.IsBase, "Initializer should call base constructor"); + + // Key validation: first argument should be the discriminator parameter, not hardcoded value + var kindArgument = initializer!.Arguments[0].ToDisplayString(); + Assert.AreEqual("kind", kindArgument, "Intermediate protected constructor should pass discriminator parameter to base, not hardcode literal"); + + // Verify derived model constructor passes discriminator correctly to intermediate + var derivedCtor = derivedProvider.Constructors.FirstOrDefault(c => c.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Public)); + Assert.IsNotNull(derivedCtor, "Derived model should have a public constructor"); + + var derivedInitializer = derivedCtor!.Signature.Initializer; + Assert.IsNotNull(derivedInitializer, "Derived constructor should have base initializer"); + Assert.IsTrue(derivedInitializer!.IsBase, "Derived initializer should call base constructor"); + + // Derived should pass its discriminator value to intermediate constructor + var derivedKindArgument = derivedInitializer!.Arguments[0].ToDisplayString(); + Assert.AreEqual("\"derived\"", derivedKindArgument, "Derived should pass its discriminator value to intermediate constructor"); + } } } diff --git a/packages/http-client-csharp/generator/TestProjects/Local.Tests/HierarchyBuildingTests.cs b/packages/http-client-csharp/generator/TestProjects/Local.Tests/HierarchyBuildingTests.cs new file mode 100644 index 00000000000..4caacf9d9a4 --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Local.Tests/HierarchyBuildingTests.cs @@ -0,0 +1,223 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Linq; +using System.Reflection; +using NUnit.Framework; +using SampleTypeSpec; + +namespace TestProjects.Local.Tests +{ + public class HierarchyBuildingTests + { + [Test] + public void DogExtendsIntermediatePetModel() + { + // Verify that Dog extends Pet (not Animal directly) due to @Legacy.hierarchyBuilding(Pet) + var dogType = typeof(Dog); + var baseType = dogType.BaseType; + + Assert.IsNotNull(baseType); + Assert.AreEqual("Pet", baseType!.Name); + } + + [Test] + public void DogHasPropertiesFromBothAnimalAndPet() + { + // Verify Dog has all properties from the hierarchy + var dogType = typeof(Dog); + + // From Animal (public) + var nameProperty = dogType.GetProperty("Name", BindingFlags.Public | BindingFlags.Instance); + + // From Pet (intermediate) + var trainedProperty = dogType.GetProperty("Trained", BindingFlags.Public | BindingFlags.Instance); + + // From Dog + var breedProperty = dogType.GetProperty("Breed", BindingFlags.Public | BindingFlags.Instance); + + Assert.IsNotNull(nameProperty, "Dog should have Name property from Animal"); + Assert.IsNotNull(trainedProperty, "Dog should have Trained property from Pet"); + Assert.IsNotNull(breedProperty, "Dog should have Breed property"); + } + + [Test] + public void PetExtendsAnimal() + { + // Verify that Pet extends Animal (normal inheritance) + var petType = typeof(Pet); + var baseType = petType.BaseType; + + Assert.IsNotNull(baseType); + Assert.AreEqual("Animal", baseType!.Name); + } + + [Test] + public void AnimalIsAbstractBaseClass() + { + // Verify Animal is the abstract discriminated base + var animalType = typeof(Animal); + + Assert.IsTrue(animalType.IsAbstract, "Animal should be abstract"); + Assert.IsTrue(animalType.IsClass, "Animal should be a class"); + } + + [Test] + public void DogInheritsFromPetNotAnimalDirectly() + { + // This is the key test for hierarchy building - Dog -> Pet -> Animal + var dogType = typeof(Dog); + var petType = typeof(Pet); + var animalType = typeof(Animal); + + // Dog's immediate base should be Pet + Assert.AreEqual(petType, dogType.BaseType, "Dog should directly extend Pet"); + + // Pet's immediate base should be Animal + Assert.AreEqual(animalType, petType.BaseType, "Pet should directly extend Animal"); + + // Dog should be assignable to both Pet and Animal + Assert.IsTrue(petType.IsAssignableFrom(dogType), "Dog should be assignable to Pet"); + Assert.IsTrue(animalType.IsAssignableFrom(dogType), "Dog should be assignable to Animal"); + } + + [Test] + public void AnimalOperationsClientExists() + { + // Verify AnimalOperations client is generated + var clientType = typeof(SampleTypeSpecClient); + var getAnimalOpsMethod = clientType.GetMethod("GetAnimalOperationsClient"); + + Assert.IsNotNull(getAnimalOpsMethod, "Client should have GetAnimalOperationsClient() method"); + Assert.AreEqual("AnimalOperations", getAnimalOpsMethod!.ReturnType.Name); + } + + [Test] + public void PetOperationsClientExists() + { + // Verify PetOperations client is generated + var clientType = typeof(SampleTypeSpecClient); + var getPetOpsMethod = clientType.GetMethod("GetPetOperationsClient"); + + Assert.IsNotNull(getPetOpsMethod, "Client should have GetPetOperationsClient() method"); + Assert.AreEqual("PetOperations", getPetOpsMethod!.ReturnType.Name); + } + + [Test] + public void DogOperationsClientExists() + { + // Verify DogOperations client is generated + var clientType = typeof(SampleTypeSpecClient); + var getDogOpsMethod = clientType.GetMethod("GetDogOperationsClient"); + + Assert.IsNotNull(getDogOpsMethod, "Client should have GetDogOperationsClient() method"); + Assert.AreEqual("DogOperations", getDogOpsMethod!.ReturnType.Name); + } + + [Test] + public void UpdateDogAsAnimalOperationExists() + { + // Verify UpdateDogAsAnimal operation exists and accepts Animal parameter + var animalOpsType = typeof(SampleTypeSpecClient).Assembly.GetType("SampleTypeSpec.AnimalOperations"); + Assert.IsNotNull(animalOpsType, "AnimalOperations type should exist"); + + var updateDogMethod = animalOpsType!.GetMethods() + .FirstOrDefault(m => m.Name == "UpdateDogAsAnimal" || m.Name == "UpdateDogAsAnimalAsync"); + + Assert.IsNotNull(updateDogMethod, "UpdateDogAsAnimal operation should exist"); + } + + [Test] + public void UpdatePetAsAnimalOperationExists() + { + // Verify UpdatePetAsAnimal operation exists and accepts Animal parameter + var animalOpsType = typeof(SampleTypeSpecClient).Assembly.GetType("SampleTypeSpec.AnimalOperations"); + Assert.IsNotNull(animalOpsType, "AnimalOperations type should exist"); + + var updatePetMethod = animalOpsType!.GetMethods() + .FirstOrDefault(m => m.Name == "UpdatePetAsAnimal" || m.Name == "UpdatePetAsAnimalAsync"); + + Assert.IsNotNull(updatePetMethod, "UpdatePetAsAnimal operation should exist"); + } + + [Test] + public void UpdateDogAsPetOperationExists() + { + // Verify UpdateDogAsPet operation exists in PetOperations + var petOpsType = typeof(SampleTypeSpecClient).Assembly.GetType("SampleTypeSpec.PetOperations"); + Assert.IsNotNull(petOpsType, "PetOperations type should exist"); + + var updateDogMethod = petOpsType!.GetMethods() + .FirstOrDefault(m => m.Name == "UpdateDogAsPet" || m.Name == "UpdateDogAsPetAsync"); + + Assert.IsNotNull(updateDogMethod, "UpdateDogAsPet operation should exist"); + } + + [Test] + public void UpdateDogAsDogOperationExists() + { + // Verify UpdateDogAsDog operation exists in DogOperations + var dogOpsType = typeof(SampleTypeSpecClient).Assembly.GetType("SampleTypeSpec.DogOperations"); + Assert.IsNotNull(dogOpsType, "DogOperations type should exist"); + + var updateDogMethod = dogOpsType!.GetMethods() + .FirstOrDefault(m => m.Name == "UpdateDogAsDog" || m.Name == "UpdateDogAsDogAsync"); + + Assert.IsNotNull(updateDogMethod, "UpdateDogAsDog operation should exist"); + } + + [Test] + public void DogCanBePassedToAnimalOperation() + { + // Verify Dog instance can be used where Animal is expected (polymorphism) + Dog dog = new Dog("Rex", true, "German Shepherd"); + Animal animal = dog; // This should compile + + Assert.IsNotNull(animal); + Assert.AreEqual("Rex", animal.Name); + + // Verify the dog can be cast back + Dog? castBack = animal as Dog; + Assert.IsNotNull(castBack); + Assert.AreEqual("German Shepherd", castBack!.Breed); + } + + [Test] + public void DogCanBePassedToPetOperation() + { + // Verify Dog instance can be used where Pet is expected (polymorphism) + Dog dog = new Dog("Rex", true, "German Shepherd"); + Pet pet = dog; + + Assert.IsNotNull(pet); + Assert.AreEqual("Rex", pet.Name); + Assert.IsTrue(pet.Trained); + + // Verify the dog can be cast back + Dog? castBack = pet as Dog; + Assert.IsNotNull(castBack); + Assert.AreEqual("German Shepherd", castBack!.Breed); + } + + [Test] + public void AllHierarchyLevelsHaveCorrectProperties() + { + // Create a dog and verify all properties through the hierarchy are accessible + Dog dog = new Dog("Rex", true, "German Shepherd"); + + // Access as Dog + Assert.AreEqual("Rex", dog.Name); + Assert.AreEqual("German Shepherd", dog.Breed); + Assert.IsTrue(dog.Trained); + + // Access as Pet + Pet pet = dog; + Assert.AreEqual("Rex", pet.Name); + Assert.IsTrue(pet.Trained); + + // Access as Animal + Animal animal = dog; + Assert.AreEqual("Rex", animal.Name); + } + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/AnimalOperations.RestClient.cs b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/AnimalOperations.RestClient.cs new file mode 100644 index 00000000000..8d8d8ffdd75 --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/AnimalOperations.RestClient.cs @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System.ClientModel; +using System.ClientModel.Primitives; + +namespace SampleTypeSpec +{ + /// + public partial class AnimalOperations + { + private static PipelineMessageClassifier _pipelineMessageClassifier200; + + private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 = PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); + + internal PipelineMessage CreateUpdatePetAsAnimalRequest(BinaryContent content, RequestOptions options) + { + ClientUriBuilder uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/animals/pet/as-animal", false); + PipelineMessage message = Pipeline.CreateMessage(uri.ToUri(), "PUT", PipelineMessageClassifier200); + PipelineRequest request = message.Request; + request.Headers.Set("Content-Type", "application/json"); + request.Headers.Set("Accept", "application/json"); + request.Content = content; + message.Apply(options); + return message; + } + + internal PipelineMessage CreateUpdateDogAsAnimalRequest(BinaryContent content, RequestOptions options) + { + ClientUriBuilder uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/animals/dog/as-animal", false); + PipelineMessage message = Pipeline.CreateMessage(uri.ToUri(), "PUT", PipelineMessageClassifier200); + PipelineRequest request = message.Request; + request.Headers.Set("Content-Type", "application/json"); + request.Headers.Set("Accept", "application/json"); + request.Content = content; + message.Apply(options); + return message; + } + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/AnimalOperations.cs b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/AnimalOperations.cs new file mode 100644 index 00000000000..10d3b31fe97 --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/AnimalOperations.cs @@ -0,0 +1,174 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Threading; +using System.Threading.Tasks; + +namespace SampleTypeSpec +{ + /// The AnimalOperations sub-client. + public partial class AnimalOperations + { + private readonly Uri _endpoint; + + /// Initializes a new instance of AnimalOperations for mocking. + protected AnimalOperations() + { + } + + /// Initializes a new instance of AnimalOperations. + /// The HTTP pipeline for sending and receiving REST requests and responses. + /// Service endpoint. + internal AnimalOperations(ClientPipeline pipeline, Uri endpoint) + { + _endpoint = endpoint; + Pipeline = pipeline; + } + + /// The HTTP pipeline for sending and receiving REST requests and responses. + public ClientPipeline Pipeline { get; } + + /// + /// [Protocol Method] Update a pet as an animal + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// The content to send as the body of the request. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult UpdatePetAsAnimal(BinaryContent content, RequestOptions options = null) + { + Argument.AssertNotNull(content, nameof(content)); + + using PipelineMessage message = CreateUpdatePetAsAnimalRequest(content, options); + return ClientResult.FromResponse(Pipeline.ProcessMessage(message, options)); + } + + /// + /// [Protocol Method] Update a pet as an animal + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// The content to send as the body of the request. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task UpdatePetAsAnimalAsync(BinaryContent content, RequestOptions options = null) + { + Argument.AssertNotNull(content, nameof(content)); + + using PipelineMessage message = CreateUpdatePetAsAnimalRequest(content, options); + return ClientResult.FromResponse(await Pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + /// Update a pet as an animal. + /// + /// The cancellation token that can be used to cancel the operation. + /// is null. + /// Service returned a non-success status code. + public virtual ClientResult UpdatePetAsAnimal(Animal animal, CancellationToken cancellationToken = default) + { + Argument.AssertNotNull(animal, nameof(animal)); + + ClientResult result = UpdatePetAsAnimal(animal, cancellationToken.ToRequestOptions()); + return ClientResult.FromValue((Animal)result, result.GetRawResponse()); + } + + /// Update a pet as an animal. + /// + /// The cancellation token that can be used to cancel the operation. + /// is null. + /// Service returned a non-success status code. + public virtual async Task> UpdatePetAsAnimalAsync(Animal animal, CancellationToken cancellationToken = default) + { + Argument.AssertNotNull(animal, nameof(animal)); + + ClientResult result = await UpdatePetAsAnimalAsync(animal, cancellationToken.ToRequestOptions()).ConfigureAwait(false); + return ClientResult.FromValue((Animal)result, result.GetRawResponse()); + } + + /// + /// [Protocol Method] Update a dog as an animal + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// The content to send as the body of the request. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult UpdateDogAsAnimal(BinaryContent content, RequestOptions options = null) + { + Argument.AssertNotNull(content, nameof(content)); + + using PipelineMessage message = CreateUpdateDogAsAnimalRequest(content, options); + return ClientResult.FromResponse(Pipeline.ProcessMessage(message, options)); + } + + /// + /// [Protocol Method] Update a dog as an animal + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// The content to send as the body of the request. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task UpdateDogAsAnimalAsync(BinaryContent content, RequestOptions options = null) + { + Argument.AssertNotNull(content, nameof(content)); + + using PipelineMessage message = CreateUpdateDogAsAnimalRequest(content, options); + return ClientResult.FromResponse(await Pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + /// Update a dog as an animal. + /// + /// The cancellation token that can be used to cancel the operation. + /// is null. + /// Service returned a non-success status code. + public virtual ClientResult UpdateDogAsAnimal(Animal animal, CancellationToken cancellationToken = default) + { + Argument.AssertNotNull(animal, nameof(animal)); + + ClientResult result = UpdateDogAsAnimal(animal, cancellationToken.ToRequestOptions()); + return ClientResult.FromValue((Animal)result, result.GetRawResponse()); + } + + /// Update a dog as an animal. + /// + /// The cancellation token that can be used to cancel the operation. + /// is null. + /// Service returned a non-success status code. + public virtual async Task> UpdateDogAsAnimalAsync(Animal animal, CancellationToken cancellationToken = default) + { + Argument.AssertNotNull(animal, nameof(animal)); + + ClientResult result = await UpdateDogAsAnimalAsync(animal, cancellationToken.ToRequestOptions()).ConfigureAwait(false); + return ClientResult.FromValue((Animal)result, result.GetRawResponse()); + } + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/DogOperations.RestClient.cs b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/DogOperations.RestClient.cs new file mode 100644 index 00000000000..ce03fb07b17 --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/DogOperations.RestClient.cs @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System.ClientModel; +using System.ClientModel.Primitives; + +namespace SampleTypeSpec +{ + /// + public partial class DogOperations + { + private static PipelineMessageClassifier _pipelineMessageClassifier200; + + private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 = PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); + + internal PipelineMessage CreateUpdateDogAsDogRequest(BinaryContent content, RequestOptions options) + { + ClientUriBuilder uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/dogs/dog/as-dog", false); + PipelineMessage message = Pipeline.CreateMessage(uri.ToUri(), "PUT", PipelineMessageClassifier200); + PipelineRequest request = message.Request; + request.Headers.Set("Content-Type", "application/json"); + request.Headers.Set("Accept", "application/json"); + request.Content = content; + message.Apply(options); + return message; + } + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/DogOperations.cs b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/DogOperations.cs new file mode 100644 index 00000000000..a45d14cb50f --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/DogOperations.cs @@ -0,0 +1,106 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Threading; +using System.Threading.Tasks; + +namespace SampleTypeSpec +{ + /// The DogOperations sub-client. + public partial class DogOperations + { + private readonly Uri _endpoint; + + /// Initializes a new instance of DogOperations for mocking. + protected DogOperations() + { + } + + /// Initializes a new instance of DogOperations. + /// The HTTP pipeline for sending and receiving REST requests and responses. + /// Service endpoint. + internal DogOperations(ClientPipeline pipeline, Uri endpoint) + { + _endpoint = endpoint; + Pipeline = pipeline; + } + + /// The HTTP pipeline for sending and receiving REST requests and responses. + public ClientPipeline Pipeline { get; } + + /// + /// [Protocol Method] Update a dog as a dog + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// The content to send as the body of the request. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult UpdateDogAsDog(BinaryContent content, RequestOptions options = null) + { + Argument.AssertNotNull(content, nameof(content)); + + using PipelineMessage message = CreateUpdateDogAsDogRequest(content, options); + return ClientResult.FromResponse(Pipeline.ProcessMessage(message, options)); + } + + /// + /// [Protocol Method] Update a dog as a dog + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// The content to send as the body of the request. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task UpdateDogAsDogAsync(BinaryContent content, RequestOptions options = null) + { + Argument.AssertNotNull(content, nameof(content)); + + using PipelineMessage message = CreateUpdateDogAsDogRequest(content, options); + return ClientResult.FromResponse(await Pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + /// Update a dog as a dog. + /// + /// The cancellation token that can be used to cancel the operation. + /// is null. + /// Service returned a non-success status code. + public virtual ClientResult UpdateDogAsDog(Dog dog, CancellationToken cancellationToken = default) + { + Argument.AssertNotNull(dog, nameof(dog)); + + ClientResult result = UpdateDogAsDog(dog, cancellationToken.ToRequestOptions()); + return ClientResult.FromValue((Dog)result, result.GetRawResponse()); + } + + /// Update a dog as a dog. + /// + /// The cancellation token that can be used to cancel the operation. + /// is null. + /// Service returned a non-success status code. + public virtual async Task> UpdateDogAsDogAsync(Dog dog, CancellationToken cancellationToken = default) + { + Argument.AssertNotNull(dog, nameof(dog)); + + ClientResult result = await UpdateDogAsDogAsync(dog, cancellationToken.ToRequestOptions()).ConfigureAwait(false); + return ClientResult.FromValue((Dog)result, result.GetRawResponse()); + } + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/Animal.Serialization.cs b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/Animal.Serialization.cs new file mode 100644 index 00000000000..36d704a717f --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/Animal.Serialization.cs @@ -0,0 +1,162 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Text.Json; + +namespace SampleTypeSpec +{ + /// + /// Base animal with discriminator + /// Please note this is the abstract base class. The derived classes available for instantiation are: and . + /// + [PersistableModelProxy(typeof(UnknownAnimal))] + public abstract partial class Animal : IJsonModel + { + /// Initializes a new instance of for deserialization. + internal Animal() + { + } + + /// The JSON writer. + /// The client options for reading and writing models. + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + writer.WriteStartObject(); + JsonModelWriteCore(writer, options); + writer.WriteEndObject(); + } + + /// The JSON writer. + /// The client options for reading and writing models. + protected virtual void JsonModelWriteCore(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(Animal)} does not support writing '{format}' format."); + } + writer.WritePropertyName("kind"u8); + writer.WriteStringValue(Kind); + writer.WritePropertyName("name"u8); + writer.WriteStringValue(Name); + if (options.Format != "W" && _additionalBinaryDataProperties != null) + { + foreach (var item in _additionalBinaryDataProperties) + { + writer.WritePropertyName(item.Key); +#if NET6_0_OR_GREATER + writer.WriteRawValue(item.Value); +#else + using (JsonDocument document = JsonDocument.Parse(item.Value)) + { + JsonSerializer.Serialize(writer, document.RootElement); + } +#endif + } + } + } + + /// The JSON reader. + /// The client options for reading and writing models. + Animal IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) => JsonModelCreateCore(ref reader, options); + + /// The JSON reader. + /// The client options for reading and writing models. + protected virtual Animal JsonModelCreateCore(ref Utf8JsonReader reader, ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(Animal)} does not support reading '{format}' format."); + } + using JsonDocument document = JsonDocument.ParseValue(ref reader); + return DeserializeAnimal(document.RootElement, options); + } + + /// The JSON element to deserialize. + /// The client options for reading and writing models. + internal static Animal DeserializeAnimal(JsonElement element, ModelReaderWriterOptions options) + { + if (element.ValueKind == JsonValueKind.Null) + { + return null; + } + if (element.TryGetProperty("kind"u8, out JsonElement discriminator)) + { + switch (discriminator.GetString()) + { + case "pet": + return Pet.DeserializePet(element, options); + case "dog": + return Dog.DeserializeDog(element, options); + } + } + return UnknownAnimal.DeserializeUnknownAnimal(element, options); + } + + /// The client options for reading and writing models. + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) => PersistableModelWriteCore(options); + + /// The client options for reading and writing models. + protected virtual BinaryData PersistableModelWriteCore(ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + switch (format) + { + case "J": + return ModelReaderWriter.Write(this, options, SampleTypeSpecContext.Default); + default: + throw new FormatException($"The model {nameof(Animal)} does not support writing '{options.Format}' format."); + } + } + + /// The data to parse. + /// The client options for reading and writing models. + Animal IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) => PersistableModelCreateCore(data, options); + + /// The data to parse. + /// The client options for reading and writing models. + protected virtual Animal PersistableModelCreateCore(BinaryData data, ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + switch (format) + { + case "J": + using (JsonDocument document = JsonDocument.Parse(data, ModelSerializationExtensions.JsonDocumentOptions)) + { + return DeserializeAnimal(document.RootElement, options); + } + default: + throw new FormatException($"The model {nameof(Animal)} does not support reading '{options.Format}' format."); + } + } + + /// The client options for reading and writing models. + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + /// The to serialize into . + public static implicit operator BinaryContent(Animal animal) + { + if (animal == null) + { + return null; + } + return BinaryContent.Create(animal, ModelSerializationExtensions.WireOptions); + } + + /// The to deserialize the from. + public static explicit operator Animal(ClientResult result) + { + PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content, ModelSerializationExtensions.JsonDocumentOptions); + return DeserializeAnimal(document.RootElement, ModelSerializationExtensions.WireOptions); + } + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/Animal.cs b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/Animal.cs new file mode 100644 index 00000000000..9843416b0e4 --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/Animal.cs @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Collections.Generic; + +namespace SampleTypeSpec +{ + /// + /// Base animal with discriminator + /// Please note this is the abstract base class. The derived classes available for instantiation are: and . + /// + public abstract partial class Animal + { + /// Keeps track of any properties unknown to the library. + private protected readonly IDictionary _additionalBinaryDataProperties; + + /// Initializes a new instance of . + /// The kind of animal. + /// Name of the animal. + private protected Animal(string kind, string name) + { + Kind = kind; + Name = name; + } + + /// Initializes a new instance of . + /// The kind of animal. + /// Name of the animal. + /// Keeps track of any properties unknown to the library. + internal Animal(string kind, string name, IDictionary additionalBinaryDataProperties) + { + Kind = kind; + Name = name; + _additionalBinaryDataProperties = additionalBinaryDataProperties; + } + + /// The kind of animal. + internal string Kind { get; set; } + + /// Name of the animal. + public string Name { get; set; } + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/Dog.Serialization.cs b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/Dog.Serialization.cs new file mode 100644 index 00000000000..470450f2c6e --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/Dog.Serialization.cs @@ -0,0 +1,165 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.Text.Json; + +namespace SampleTypeSpec +{ + /// Dog is a specific type of pet with hierarchy building. + public partial class Dog : Pet, IJsonModel + { + /// Initializes a new instance of for deserialization. + internal Dog() + { + } + + /// The JSON writer. + /// The client options for reading and writing models. + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + writer.WriteStartObject(); + JsonModelWriteCore(writer, options); + writer.WriteEndObject(); + } + + /// The JSON writer. + /// The client options for reading and writing models. + protected override void JsonModelWriteCore(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(Dog)} does not support writing '{format}' format."); + } + base.JsonModelWriteCore(writer, options); + writer.WritePropertyName("breed"u8); + writer.WriteStringValue(Breed); + } + + /// The JSON reader. + /// The client options for reading and writing models. + Dog IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) => (Dog)JsonModelCreateCore(ref reader, options); + + /// The JSON reader. + /// The client options for reading and writing models. + protected override Animal JsonModelCreateCore(ref Utf8JsonReader reader, ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(Dog)} does not support reading '{format}' format."); + } + using JsonDocument document = JsonDocument.ParseValue(ref reader); + return DeserializeDog(document.RootElement, options); + } + + /// The JSON element to deserialize. + /// The client options for reading and writing models. + internal static Dog DeserializeDog(JsonElement element, ModelReaderWriterOptions options) + { + if (element.ValueKind == JsonValueKind.Null) + { + return null; + } + string kind = "dog"; + string name = default; + IDictionary additionalBinaryDataProperties = new ChangeTrackingDictionary(); + bool trained = default; + string breed = default; + foreach (var prop in element.EnumerateObject()) + { + if (prop.NameEquals("kind"u8)) + { + kind = prop.Value.GetString(); + continue; + } + if (prop.NameEquals("name"u8)) + { + name = prop.Value.GetString(); + continue; + } + if (prop.NameEquals("trained"u8)) + { + trained = prop.Value.GetBoolean(); + continue; + } + if (prop.NameEquals("breed"u8)) + { + breed = prop.Value.GetString(); + continue; + } + if (options.Format != "W") + { + additionalBinaryDataProperties.Add(prop.Name, BinaryData.FromString(prop.Value.GetRawText())); + } + } + return new Dog(kind, name, additionalBinaryDataProperties, trained, breed); + } + + /// The client options for reading and writing models. + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) => PersistableModelWriteCore(options); + + /// The client options for reading and writing models. + protected override BinaryData PersistableModelWriteCore(ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + switch (format) + { + case "J": + return ModelReaderWriter.Write(this, options, SampleTypeSpecContext.Default); + default: + throw new FormatException($"The model {nameof(Dog)} does not support writing '{options.Format}' format."); + } + } + + /// The data to parse. + /// The client options for reading and writing models. + Dog IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) => (Dog)PersistableModelCreateCore(data, options); + + /// The data to parse. + /// The client options for reading and writing models. + protected override Animal PersistableModelCreateCore(BinaryData data, ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + switch (format) + { + case "J": + using (JsonDocument document = JsonDocument.Parse(data, ModelSerializationExtensions.JsonDocumentOptions)) + { + return DeserializeDog(document.RootElement, options); + } + default: + throw new FormatException($"The model {nameof(Dog)} does not support reading '{options.Format}' format."); + } + } + + /// The client options for reading and writing models. + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + /// The to serialize into . + public static implicit operator BinaryContent(Dog dog) + { + if (dog == null) + { + return null; + } + return BinaryContent.Create(dog, ModelSerializationExtensions.WireOptions); + } + + /// The to deserialize the from. + public static explicit operator Dog(ClientResult result) + { + PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content, ModelSerializationExtensions.JsonDocumentOptions); + return DeserializeDog(document.RootElement, ModelSerializationExtensions.WireOptions); + } + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/Dog.cs b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/Dog.cs new file mode 100644 index 00000000000..d421fa5094d --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/Dog.cs @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Collections.Generic; + +namespace SampleTypeSpec +{ + /// Dog is a specific type of pet with hierarchy building. + public partial class Dog : Pet + { + /// Initializes a new instance of . + /// Name of the animal. + /// Whether the pet is trained. + /// The breed of the dog. + /// or is null. + public Dog(string name, bool trained, string breed) : base("dog", name, trained) + { + Argument.AssertNotNull(name, nameof(name)); + Argument.AssertNotNull(breed, nameof(breed)); + + Breed = breed; + } + + /// Initializes a new instance of . + /// The kind of animal. + /// Name of the animal. + /// Keeps track of any properties unknown to the library. + /// Whether the pet is trained. + /// The breed of the dog. + internal Dog(string kind, string name, IDictionary additionalBinaryDataProperties, bool trained, string breed) : base(kind, name, additionalBinaryDataProperties, trained) + { + Breed = breed; + } + + /// The breed of the dog. + public string Breed { get; set; } + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/Pet.Serialization.cs b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/Pet.Serialization.cs new file mode 100644 index 00000000000..d6002edfbc6 --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/Pet.Serialization.cs @@ -0,0 +1,132 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Text.Json; + +namespace SampleTypeSpec +{ + /// Pet is a discriminated animal. + public partial class Pet : Animal, IJsonModel + { + /// Initializes a new instance of for deserialization. + internal Pet() + { + } + + /// The JSON writer. + /// The client options for reading and writing models. + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + writer.WriteStartObject(); + JsonModelWriteCore(writer, options); + writer.WriteEndObject(); + } + + /// The JSON writer. + /// The client options for reading and writing models. + protected override void JsonModelWriteCore(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(Pet)} does not support writing '{format}' format."); + } + base.JsonModelWriteCore(writer, options); + writer.WritePropertyName("trained"u8); + writer.WriteBooleanValue(Trained); + } + + /// The JSON reader. + /// The client options for reading and writing models. + Pet IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) => (Pet)JsonModelCreateCore(ref reader, options); + + /// The JSON reader. + /// The client options for reading and writing models. + protected override Animal JsonModelCreateCore(ref Utf8JsonReader reader, ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(Pet)} does not support reading '{format}' format."); + } + using JsonDocument document = JsonDocument.ParseValue(ref reader); + return DeserializePet(document.RootElement, options); + } + + /// The JSON element to deserialize. + /// The client options for reading and writing models. + internal static Pet DeserializePet(JsonElement element, ModelReaderWriterOptions options) + { + if (element.ValueKind == JsonValueKind.Null) + { + return null; + } + return UnknownPet.DeserializeUnknownPet(element, options); + } + + /// The client options for reading and writing models. + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) => PersistableModelWriteCore(options); + + /// The client options for reading and writing models. + protected override BinaryData PersistableModelWriteCore(ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + switch (format) + { + case "J": + return ModelReaderWriter.Write(this, options, SampleTypeSpecContext.Default); + default: + throw new FormatException($"The model {nameof(Pet)} does not support writing '{options.Format}' format."); + } + } + + /// The data to parse. + /// The client options for reading and writing models. + Pet IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) => (Pet)PersistableModelCreateCore(data, options); + + /// The data to parse. + /// The client options for reading and writing models. + protected override Animal PersistableModelCreateCore(BinaryData data, ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + switch (format) + { + case "J": + using (JsonDocument document = JsonDocument.Parse(data, ModelSerializationExtensions.JsonDocumentOptions)) + { + return DeserializePet(document.RootElement, options); + } + default: + throw new FormatException($"The model {nameof(Pet)} does not support reading '{options.Format}' format."); + } + } + + /// The client options for reading and writing models. + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + /// The to serialize into . + public static implicit operator BinaryContent(Pet pet) + { + if (pet == null) + { + return null; + } + return BinaryContent.Create(pet, ModelSerializationExtensions.WireOptions); + } + + /// The to deserialize the from. + public static explicit operator Pet(ClientResult result) + { + PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content, ModelSerializationExtensions.JsonDocumentOptions); + return DeserializePet(document.RootElement, ModelSerializationExtensions.WireOptions); + } + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/Pet.cs b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/Pet.cs new file mode 100644 index 00000000000..b91fc297ad0 --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/Pet.cs @@ -0,0 +1,49 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Collections.Generic; + +namespace SampleTypeSpec +{ + /// Pet is a discriminated animal. + public partial class Pet : Animal + { + /// Initializes a new instance of . + /// Name of the animal. + /// Whether the pet is trained. + /// is null. + public Pet(string name, bool trained) : base("pet", name) + { + Argument.AssertNotNull(name, nameof(name)); + + Trained = trained; + } + + /// Initializes a new instance of . + /// The kind of animal. + /// Name of the animal. + /// Keeps track of any properties unknown to the library. + /// Whether the pet is trained. + internal Pet(string kind, string name, IDictionary additionalBinaryDataProperties, bool trained) : base(kind, name, additionalBinaryDataProperties) + { + Trained = trained; + } + + /// Initializes a new instance of . + /// The kind of animal. + /// Name of the animal. + /// Whether the pet is trained. + private protected Pet(string kind, string name, bool trained) : base(kind, name) + { + Trained = trained; + } + + /// Whether the pet is trained. + public bool Trained { get; set; } + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/SampleTypeSpecContext.cs b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/SampleTypeSpecContext.cs index 3d2c3e12a48..2a2fe6a977f 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/SampleTypeSpecContext.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/SampleTypeSpecContext.cs @@ -14,7 +14,9 @@ namespace SampleTypeSpec /// Context class which will be filled in by the System.ClientModel.SourceGeneration. /// For more information /// + [ModelReaderWriterBuildable(typeof(Animal))] [ModelReaderWriterBuildable(typeof(AnotherDynamicModel))] + [ModelReaderWriterBuildable(typeof(Dog))] [ModelReaderWriterBuildable(typeof(DynamicModel))] [ModelReaderWriterBuildable(typeof(Friend))] [ModelReaderWriterBuildable(typeof(GetWidgetMetricsResponse))] @@ -25,10 +27,13 @@ namespace SampleTypeSpec [ModelReaderWriterBuildable(typeof(ModelWithEmbeddedNonBodyParameters))] [ModelReaderWriterBuildable(typeof(ModelWithRequiredNullableProperties))] [ModelReaderWriterBuildable(typeof(PageThing))] + [ModelReaderWriterBuildable(typeof(Pet))] [ModelReaderWriterBuildable(typeof(RenamedModelCustom))] [ModelReaderWriterBuildable(typeof(ReturnsAnonymousModelResponse))] [ModelReaderWriterBuildable(typeof(RoundTripModel))] [ModelReaderWriterBuildable(typeof(Thing))] + [ModelReaderWriterBuildable(typeof(UnknownAnimal))] + [ModelReaderWriterBuildable(typeof(UnknownPet))] public partial class SampleTypeSpecContext : ModelReaderWriterContext { } diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/UnknownAnimal.Serialization.cs b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/UnknownAnimal.Serialization.cs new file mode 100644 index 00000000000..535dd928e85 --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/UnknownAnimal.Serialization.cs @@ -0,0 +1,131 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.Text.Json; + +namespace SampleTypeSpec +{ + internal partial class UnknownAnimal : Animal, IJsonModel + { + /// Initializes a new instance of for deserialization. + internal UnknownAnimal() + { + } + + /// The JSON writer. + /// The client options for reading and writing models. + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + writer.WriteStartObject(); + JsonModelWriteCore(writer, options); + writer.WriteEndObject(); + } + + /// The JSON writer. + /// The client options for reading and writing models. + protected override void JsonModelWriteCore(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(Animal)} does not support writing '{format}' format."); + } + base.JsonModelWriteCore(writer, options); + } + + /// The JSON reader. + /// The client options for reading and writing models. + Animal IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) => JsonModelCreateCore(ref reader, options); + + /// The JSON reader. + /// The client options for reading and writing models. + protected override Animal JsonModelCreateCore(ref Utf8JsonReader reader, ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(Animal)} does not support reading '{format}' format."); + } + using JsonDocument document = JsonDocument.ParseValue(ref reader); + return DeserializeAnimal(document.RootElement, options); + } + + /// The JSON element to deserialize. + /// The client options for reading and writing models. + internal static UnknownAnimal DeserializeUnknownAnimal(JsonElement element, ModelReaderWriterOptions options) + { + if (element.ValueKind == JsonValueKind.Null) + { + return null; + } + string kind = "unknown"; + string name = default; + IDictionary additionalBinaryDataProperties = new ChangeTrackingDictionary(); + foreach (var prop in element.EnumerateObject()) + { + if (prop.NameEquals("kind"u8)) + { + kind = prop.Value.GetString(); + continue; + } + if (prop.NameEquals("name"u8)) + { + name = prop.Value.GetString(); + continue; + } + if (options.Format != "W") + { + additionalBinaryDataProperties.Add(prop.Name, BinaryData.FromString(prop.Value.GetRawText())); + } + } + return new UnknownAnimal(kind, name, additionalBinaryDataProperties); + } + + /// The client options for reading and writing models. + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) => PersistableModelWriteCore(options); + + /// The client options for reading and writing models. + protected override BinaryData PersistableModelWriteCore(ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + switch (format) + { + case "J": + return ModelReaderWriter.Write(this, options, SampleTypeSpecContext.Default); + default: + throw new FormatException($"The model {nameof(Animal)} does not support writing '{options.Format}' format."); + } + } + + /// The data to parse. + /// The client options for reading and writing models. + Animal IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) => PersistableModelCreateCore(data, options); + + /// The data to parse. + /// The client options for reading and writing models. + protected override Animal PersistableModelCreateCore(BinaryData data, ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + switch (format) + { + case "J": + using (JsonDocument document = JsonDocument.Parse(data, ModelSerializationExtensions.JsonDocumentOptions)) + { + return DeserializeAnimal(document.RootElement, options); + } + default: + throw new FormatException($"The model {nameof(Animal)} does not support reading '{options.Format}' format."); + } + } + + /// The client options for reading and writing models. + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/UnknownAnimal.cs b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/UnknownAnimal.cs new file mode 100644 index 00000000000..11b9d39207e --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/UnknownAnimal.cs @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Collections.Generic; + +namespace SampleTypeSpec +{ + internal partial class UnknownAnimal : Animal + { + /// Initializes a new instance of . + /// The kind of animal. + /// Name of the animal. + /// Keeps track of any properties unknown to the library. + internal UnknownAnimal(string kind, string name, IDictionary additionalBinaryDataProperties) : base(kind ?? "unknown", name, additionalBinaryDataProperties) + { + } + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/UnknownPet.Serialization.cs b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/UnknownPet.Serialization.cs new file mode 100644 index 00000000000..b0074ad04b3 --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/UnknownPet.Serialization.cs @@ -0,0 +1,137 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.Text.Json; + +namespace SampleTypeSpec +{ + internal partial class UnknownPet : Pet, IJsonModel + { + /// Initializes a new instance of for deserialization. + internal UnknownPet() + { + } + + /// The JSON writer. + /// The client options for reading and writing models. + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + writer.WriteStartObject(); + JsonModelWriteCore(writer, options); + writer.WriteEndObject(); + } + + /// The JSON writer. + /// The client options for reading and writing models. + protected override void JsonModelWriteCore(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(Pet)} does not support writing '{format}' format."); + } + base.JsonModelWriteCore(writer, options); + } + + /// The JSON reader. + /// The client options for reading and writing models. + Pet IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) => (UnknownPet)JsonModelCreateCore(ref reader, options); + + /// The JSON reader. + /// The client options for reading and writing models. + protected override Animal JsonModelCreateCore(ref Utf8JsonReader reader, ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(Pet)} does not support reading '{format}' format."); + } + using JsonDocument document = JsonDocument.ParseValue(ref reader); + return DeserializePet(document.RootElement, options); + } + + /// The JSON element to deserialize. + /// The client options for reading and writing models. + internal static UnknownPet DeserializeUnknownPet(JsonElement element, ModelReaderWriterOptions options) + { + if (element.ValueKind == JsonValueKind.Null) + { + return null; + } + string kind = "unknown"; + string name = default; + IDictionary additionalBinaryDataProperties = new ChangeTrackingDictionary(); + bool trained = default; + foreach (var prop in element.EnumerateObject()) + { + if (prop.NameEquals("kind"u8)) + { + kind = prop.Value.GetString(); + continue; + } + if (prop.NameEquals("name"u8)) + { + name = prop.Value.GetString(); + continue; + } + if (prop.NameEquals("trained"u8)) + { + trained = prop.Value.GetBoolean(); + continue; + } + if (options.Format != "W") + { + additionalBinaryDataProperties.Add(prop.Name, BinaryData.FromString(prop.Value.GetRawText())); + } + } + return new UnknownPet(kind, name, additionalBinaryDataProperties, trained); + } + + /// The client options for reading and writing models. + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) => PersistableModelWriteCore(options); + + /// The client options for reading and writing models. + protected override BinaryData PersistableModelWriteCore(ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + switch (format) + { + case "J": + return ModelReaderWriter.Write(this, options, SampleTypeSpecContext.Default); + default: + throw new FormatException($"The model {nameof(Pet)} does not support writing '{options.Format}' format."); + } + } + + /// The data to parse. + /// The client options for reading and writing models. + Pet IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) => (UnknownPet)PersistableModelCreateCore(data, options); + + /// The data to parse. + /// The client options for reading and writing models. + protected override Animal PersistableModelCreateCore(BinaryData data, ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + switch (format) + { + case "J": + using (JsonDocument document = JsonDocument.Parse(data, ModelSerializationExtensions.JsonDocumentOptions)) + { + return DeserializePet(document.RootElement, options); + } + default: + throw new FormatException($"The model {nameof(Pet)} does not support reading '{options.Format}' format."); + } + } + + /// The client options for reading and writing models. + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/UnknownPet.cs b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/UnknownPet.cs new file mode 100644 index 00000000000..a318bf4fd07 --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/UnknownPet.cs @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Collections.Generic; + +namespace SampleTypeSpec +{ + internal partial class UnknownPet : Pet + { + /// Initializes a new instance of . + /// The kind of animal. + /// Name of the animal. + /// Keeps track of any properties unknown to the library. + /// Whether the pet is trained. + internal UnknownPet(string kind, string name, IDictionary additionalBinaryDataProperties, bool trained) : base(kind ?? "unknown", name, additionalBinaryDataProperties, trained) + { + } + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/PetOperations.RestClient.cs b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/PetOperations.RestClient.cs new file mode 100644 index 00000000000..6681f9e7d79 --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/PetOperations.RestClient.cs @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System.ClientModel; +using System.ClientModel.Primitives; + +namespace SampleTypeSpec +{ + /// + public partial class PetOperations + { + private static PipelineMessageClassifier _pipelineMessageClassifier200; + + private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 = PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); + + internal PipelineMessage CreateUpdatePetAsPetRequest(BinaryContent content, RequestOptions options) + { + ClientUriBuilder uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/pets/pet/as-pet", false); + PipelineMessage message = Pipeline.CreateMessage(uri.ToUri(), "PUT", PipelineMessageClassifier200); + PipelineRequest request = message.Request; + request.Headers.Set("Content-Type", "application/json"); + request.Headers.Set("Accept", "application/json"); + request.Content = content; + message.Apply(options); + return message; + } + + internal PipelineMessage CreateUpdateDogAsPetRequest(BinaryContent content, RequestOptions options) + { + ClientUriBuilder uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/pets/dog/as-pet", false); + PipelineMessage message = Pipeline.CreateMessage(uri.ToUri(), "PUT", PipelineMessageClassifier200); + PipelineRequest request = message.Request; + request.Headers.Set("Content-Type", "application/json"); + request.Headers.Set("Accept", "application/json"); + request.Content = content; + message.Apply(options); + return message; + } + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/PetOperations.cs b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/PetOperations.cs new file mode 100644 index 00000000000..7f7531baa9d --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/PetOperations.cs @@ -0,0 +1,174 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Threading; +using System.Threading.Tasks; + +namespace SampleTypeSpec +{ + /// The PetOperations sub-client. + public partial class PetOperations + { + private readonly Uri _endpoint; + + /// Initializes a new instance of PetOperations for mocking. + protected PetOperations() + { + } + + /// Initializes a new instance of PetOperations. + /// The HTTP pipeline for sending and receiving REST requests and responses. + /// Service endpoint. + internal PetOperations(ClientPipeline pipeline, Uri endpoint) + { + _endpoint = endpoint; + Pipeline = pipeline; + } + + /// The HTTP pipeline for sending and receiving REST requests and responses. + public ClientPipeline Pipeline { get; } + + /// + /// [Protocol Method] Update a pet as a pet + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// The content to send as the body of the request. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult UpdatePetAsPet(BinaryContent content, RequestOptions options = null) + { + Argument.AssertNotNull(content, nameof(content)); + + using PipelineMessage message = CreateUpdatePetAsPetRequest(content, options); + return ClientResult.FromResponse(Pipeline.ProcessMessage(message, options)); + } + + /// + /// [Protocol Method] Update a pet as a pet + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// The content to send as the body of the request. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task UpdatePetAsPetAsync(BinaryContent content, RequestOptions options = null) + { + Argument.AssertNotNull(content, nameof(content)); + + using PipelineMessage message = CreateUpdatePetAsPetRequest(content, options); + return ClientResult.FromResponse(await Pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + /// Update a pet as a pet. + /// + /// The cancellation token that can be used to cancel the operation. + /// is null. + /// Service returned a non-success status code. + public virtual ClientResult UpdatePetAsPet(Pet pet, CancellationToken cancellationToken = default) + { + Argument.AssertNotNull(pet, nameof(pet)); + + ClientResult result = UpdatePetAsPet(pet, cancellationToken.ToRequestOptions()); + return ClientResult.FromValue((Pet)result, result.GetRawResponse()); + } + + /// Update a pet as a pet. + /// + /// The cancellation token that can be used to cancel the operation. + /// is null. + /// Service returned a non-success status code. + public virtual async Task> UpdatePetAsPetAsync(Pet pet, CancellationToken cancellationToken = default) + { + Argument.AssertNotNull(pet, nameof(pet)); + + ClientResult result = await UpdatePetAsPetAsync(pet, cancellationToken.ToRequestOptions()).ConfigureAwait(false); + return ClientResult.FromValue((Pet)result, result.GetRawResponse()); + } + + /// + /// [Protocol Method] Update a dog as a pet + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// The content to send as the body of the request. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult UpdateDogAsPet(BinaryContent content, RequestOptions options = null) + { + Argument.AssertNotNull(content, nameof(content)); + + using PipelineMessage message = CreateUpdateDogAsPetRequest(content, options); + return ClientResult.FromResponse(Pipeline.ProcessMessage(message, options)); + } + + /// + /// [Protocol Method] Update a dog as a pet + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// The content to send as the body of the request. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task UpdateDogAsPetAsync(BinaryContent content, RequestOptions options = null) + { + Argument.AssertNotNull(content, nameof(content)); + + using PipelineMessage message = CreateUpdateDogAsPetRequest(content, options); + return ClientResult.FromResponse(await Pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + /// Update a dog as a pet. + /// + /// The cancellation token that can be used to cancel the operation. + /// is null. + /// Service returned a non-success status code. + public virtual ClientResult UpdateDogAsPet(Pet pet, CancellationToken cancellationToken = default) + { + Argument.AssertNotNull(pet, nameof(pet)); + + ClientResult result = UpdateDogAsPet(pet, cancellationToken.ToRequestOptions()); + return ClientResult.FromValue((Pet)result, result.GetRawResponse()); + } + + /// Update a dog as a pet. + /// + /// The cancellation token that can be used to cancel the operation. + /// is null. + /// Service returned a non-success status code. + public virtual async Task> UpdateDogAsPetAsync(Pet pet, CancellationToken cancellationToken = default) + { + Argument.AssertNotNull(pet, nameof(pet)); + + ClientResult result = await UpdateDogAsPetAsync(pet, cancellationToken.ToRequestOptions()).ConfigureAwait(false); + return ClientResult.FromValue((Pet)result, result.GetRawResponse()); + } + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/SampleTypeSpecClient.cs b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/SampleTypeSpecClient.cs index c03b2d8da99..fe4644f654f 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/SampleTypeSpecClient.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/SampleTypeSpecClient.cs @@ -36,6 +36,9 @@ public partial class SampleTypeSpecClient } }; private readonly string _apiVersion; + private AnimalOperations _cachedAnimalOperations; + private PetOperations _cachedPetOperations; + private DogOperations _cachedDogOperations; private Metrics _cachedMetrics; /// Initializes a new instance of SampleTypeSpecClient for mocking. @@ -1720,6 +1723,24 @@ public virtual async Task DynamicModelOperationAsync(DynamicModel return await DynamicModelOperationAsync(body, cancellationToken.ToRequestOptions()).ConfigureAwait(false); } + /// Initializes a new instance of AnimalOperations. + public virtual AnimalOperations GetAnimalOperationsClient() + { + return Volatile.Read(ref _cachedAnimalOperations) ?? Interlocked.CompareExchange(ref _cachedAnimalOperations, new AnimalOperations(Pipeline, _endpoint), null) ?? _cachedAnimalOperations; + } + + /// Initializes a new instance of PetOperations. + public virtual PetOperations GetPetOperationsClient() + { + return Volatile.Read(ref _cachedPetOperations) ?? Interlocked.CompareExchange(ref _cachedPetOperations, new PetOperations(Pipeline, _endpoint), null) ?? _cachedPetOperations; + } + + /// Initializes a new instance of DogOperations. + public virtual DogOperations GetDogOperationsClient() + { + return Volatile.Read(ref _cachedDogOperations) ?? Interlocked.CompareExchange(ref _cachedDogOperations, new DogOperations(Pipeline, _endpoint), null) ?? _cachedDogOperations; + } + /// Initializes a new instance of Metrics. public virtual Metrics GetMetricsClient() { diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/SampleTypeSpecModelFactory.cs b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/SampleTypeSpecModelFactory.cs index 1bee9ea6640..f16d669f0d6 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/SampleTypeSpecModelFactory.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/SampleTypeSpecModelFactory.cs @@ -231,6 +231,37 @@ public static AnotherDynamicModel AnotherDynamicModel(string bar = default) return new AnotherDynamicModel(bar, default); } + /// + /// Base animal with discriminator + /// Please note this is the abstract base class. The derived classes available for instantiation are: and . + /// + /// The kind of animal. + /// Name of the animal. + /// A new instance for mocking. + public static Animal Animal(string kind = default, string name = default) + { + return new UnknownAnimal(kind, name, additionalBinaryDataProperties: null); + } + + /// Pet is a discriminated animal. + /// Name of the animal. + /// Whether the pet is trained. + /// A new instance for mocking. + public static Pet Pet(string name = default, bool trained = default) + { + return new Pet("pet", name, additionalBinaryDataProperties: null, trained); + } + + /// Dog is a specific type of pet with hierarchy building. + /// Name of the animal. + /// Whether the pet is trained. + /// The breed of the dog. + /// A new instance for mocking. + public static Dog Dog(string name = default, bool trained = default, string breed = default) + { + return new Dog("pet", name, additionalBinaryDataProperties: null, trained, breed); + } + /// The GetWidgetMetricsResponse. /// /// diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/tspCodeModel.json b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/tspCodeModel.json index 84c243dbc7c..e92b37559b9 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/tspCodeModel.json +++ b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/tspCodeModel.json @@ -879,9 +879,9 @@ { "$id": "80", "kind": "constant", - "name": "sayHiContentType", - "namespace": "", - "usage": "None", + "name": "PetKind", + "namespace": "SampleTypeSpec", + "usage": "Input,Output,Json", "valueType": { "$id": "81", "kind": "string", @@ -889,15 +889,15 @@ "crossLanguageDefinitionId": "TypeSpec.string", "decorators": [] }, - "value": "application/json", + "value": "pet", "decorators": [] }, { "$id": "82", "kind": "constant", - "name": "HelloAgainRequestContentType", - "namespace": "", - "usage": "None", + "name": "DogKind", + "namespace": "SampleTypeSpec", + "usage": "Input,Output,Json", "valueType": { "$id": "83", "kind": "string", @@ -905,13 +905,13 @@ "crossLanguageDefinitionId": "TypeSpec.string", "decorators": [] }, - "value": "text/plain", + "value": "dog", "decorators": [] }, { "$id": "84", "kind": "constant", - "name": "helloAgainContentType", + "name": "sayHiContentType", "namespace": "", "usage": "None", "valueType": { @@ -927,7 +927,7 @@ { "$id": "86", "kind": "constant", - "name": "HelloAgainRequestContentType1", + "name": "HelloAgainRequestContentType", "namespace": "", "usage": "None", "valueType": { @@ -943,7 +943,7 @@ { "$id": "88", "kind": "constant", - "name": "noContentTypeContentType", + "name": "helloAgainContentType", "namespace": "", "usage": "None", "valueType": { @@ -959,7 +959,7 @@ { "$id": "90", "kind": "constant", - "name": "noContentTypeContentType1", + "name": "HelloAgainRequestContentType1", "namespace": "", "usage": "None", "valueType": { @@ -969,13 +969,13 @@ "crossLanguageDefinitionId": "TypeSpec.string", "decorators": [] }, - "value": "application/json", + "value": "text/plain", "decorators": [] }, { "$id": "92", "kind": "constant", - "name": "helloDemo2ContentType", + "name": "noContentTypeContentType", "namespace": "", "usage": "None", "valueType": { @@ -991,7 +991,7 @@ { "$id": "94", "kind": "constant", - "name": "createLiteralContentType", + "name": "noContentTypeContentType1", "namespace": "", "usage": "None", "valueType": { @@ -1007,7 +1007,7 @@ { "$id": "96", "kind": "constant", - "name": "createLiteralContentType1", + "name": "helloDemo2ContentType", "namespace": "", "usage": "None", "valueType": { @@ -1023,7 +1023,7 @@ { "$id": "98", "kind": "constant", - "name": "HelloLiteralRequestP1", + "name": "createLiteralContentType", "namespace": "", "usage": "None", "valueType": { @@ -1033,17 +1033,49 @@ "crossLanguageDefinitionId": "TypeSpec.string", "decorators": [] }, - "value": "test", + "value": "application/json", "decorators": [] }, { "$id": "100", "kind": "constant", - "name": "ThingRequiredLiteralInt1", + "name": "createLiteralContentType1", "namespace": "", "usage": "None", "valueType": { "$id": "101", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "value": "application/json", + "decorators": [] + }, + { + "$id": "102", + "kind": "constant", + "name": "HelloLiteralRequestP1", + "namespace": "", + "usage": "None", + "valueType": { + "$id": "103", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "value": "test", + "decorators": [] + }, + { + "$id": "104", + "kind": "constant", + "name": "ThingRequiredLiteralInt1", + "namespace": "", + "usage": "None", + "valueType": { + "$id": "105", "kind": "int32", "name": "int32", "crossLanguageDefinitionId": "TypeSpec.int32", @@ -1053,13 +1085,13 @@ "decorators": [] }, { - "$id": "102", + "$id": "106", "kind": "constant", "name": "ThingOptionalLiteralBool1", "namespace": "", "usage": "None", "valueType": { - "$id": "103", + "$id": "107", "kind": "boolean", "name": "boolean", "crossLanguageDefinitionId": "TypeSpec.boolean", @@ -1069,13 +1101,13 @@ "decorators": [] }, { - "$id": "104", + "$id": "108", "kind": "constant", "name": "helloLiteralContentType", "namespace": "", "usage": "None", "valueType": { - "$id": "105", + "$id": "109", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1085,13 +1117,13 @@ "decorators": [] }, { - "$id": "106", + "$id": "110", "kind": "constant", "name": "HelloLiteralRequestP11", "namespace": "", "usage": "None", "valueType": { - "$id": "107", + "$id": "111", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1101,13 +1133,13 @@ "decorators": [] }, { - "$id": "108", + "$id": "112", "kind": "constant", "name": "ThingRequiredLiteralInt2", "namespace": "", "usage": "None", "valueType": { - "$id": "109", + "$id": "113", "kind": "int32", "name": "int32", "crossLanguageDefinitionId": "TypeSpec.int32", @@ -1117,13 +1149,13 @@ "decorators": [] }, { - "$id": "110", + "$id": "114", "kind": "constant", "name": "ThingOptionalLiteralBool2", "namespace": "", "usage": "None", "valueType": { - "$id": "111", + "$id": "115", "kind": "boolean", "name": "boolean", "crossLanguageDefinitionId": "TypeSpec.boolean", @@ -1133,13 +1165,13 @@ "decorators": [] }, { - "$id": "112", + "$id": "116", "kind": "constant", "name": "topActionContentType", "namespace": "", "usage": "None", "valueType": { - "$id": "113", + "$id": "117", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1149,13 +1181,13 @@ "decorators": [] }, { - "$id": "114", + "$id": "118", "kind": "constant", "name": "topAction2ContentType", "namespace": "", "usage": "None", "valueType": { - "$id": "115", + "$id": "119", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1165,13 +1197,13 @@ "decorators": [] }, { - "$id": "116", + "$id": "120", "kind": "constant", "name": "patchActionContentType", "namespace": "", "usage": "None", "valueType": { - "$id": "117", + "$id": "121", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1181,13 +1213,13 @@ "decorators": [] }, { - "$id": "118", + "$id": "122", "kind": "constant", "name": "patchActionContentType1", "namespace": "", "usage": "None", "valueType": { - "$id": "119", + "$id": "123", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1197,13 +1229,13 @@ "decorators": [] }, { - "$id": "120", + "$id": "124", "kind": "constant", "name": "AnonymousBodyRequestRequiredQueryParam", "namespace": "", "usage": "None", "valueType": { - "$id": "121", + "$id": "125", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1213,13 +1245,13 @@ "decorators": [] }, { - "$id": "122", + "$id": "126", "kind": "constant", "name": "AnonymousBodyRequestRequiredHeader", "namespace": "", "usage": "None", "valueType": { - "$id": "123", + "$id": "127", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1229,13 +1261,13 @@ "decorators": [] }, { - "$id": "124", + "$id": "128", "kind": "constant", "name": "anonymousBodyContentType", "namespace": "", "usage": "None", "valueType": { - "$id": "125", + "$id": "129", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1245,13 +1277,13 @@ "decorators": [] }, { - "$id": "126", + "$id": "130", "kind": "constant", "name": "anonymousBodyContentType1", "namespace": "", "usage": "None", "valueType": { - "$id": "127", + "$id": "131", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1261,13 +1293,13 @@ "decorators": [] }, { - "$id": "128", + "$id": "132", "kind": "constant", "name": "ThingRequiredLiteralString1", "namespace": "", "usage": "None", "valueType": { - "$id": "129", + "$id": "133", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1277,13 +1309,13 @@ "decorators": [] }, { - "$id": "130", + "$id": "134", "kind": "constant", "name": "ThingRequiredLiteralInt3", "namespace": "", "usage": "None", "valueType": { - "$id": "131", + "$id": "135", "kind": "int32", "name": "int32", "crossLanguageDefinitionId": "TypeSpec.int32", @@ -1293,13 +1325,13 @@ "decorators": [] }, { - "$id": "132", + "$id": "136", "kind": "constant", "name": "ThingRequiredLiteralFloat1", "namespace": "", "usage": "None", "valueType": { - "$id": "133", + "$id": "137", "kind": "float32", "name": "float32", "crossLanguageDefinitionId": "TypeSpec.float32", @@ -1309,13 +1341,13 @@ "decorators": [] }, { - "$id": "134", + "$id": "138", "kind": "constant", "name": "ThingRequiredLiteralBool1", "namespace": "", "usage": "None", "valueType": { - "$id": "135", + "$id": "139", "kind": "boolean", "name": "boolean", "crossLanguageDefinitionId": "TypeSpec.boolean", @@ -1325,13 +1357,13 @@ "decorators": [] }, { - "$id": "136", + "$id": "140", "kind": "constant", "name": "ThingOptionalLiteralBool3", "namespace": "", "usage": "None", "valueType": { - "$id": "137", + "$id": "141", "kind": "boolean", "name": "boolean", "crossLanguageDefinitionId": "TypeSpec.boolean", @@ -1341,13 +1373,13 @@ "decorators": [] }, { - "$id": "138", + "$id": "142", "kind": "constant", "name": "AnonymousBodyRequestRequiredQueryParam1", "namespace": "", "usage": "None", "valueType": { - "$id": "139", + "$id": "143", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1357,13 +1389,13 @@ "decorators": [] }, { - "$id": "140", + "$id": "144", "kind": "constant", "name": "AnonymousBodyRequestRequiredHeader1", "namespace": "", "usage": "None", "valueType": { - "$id": "141", + "$id": "145", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1373,13 +1405,13 @@ "decorators": [] }, { - "$id": "142", + "$id": "146", "kind": "constant", "name": "friendlyModelContentType", "namespace": "", "usage": "None", "valueType": { - "$id": "143", + "$id": "147", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1389,13 +1421,13 @@ "decorators": [] }, { - "$id": "144", + "$id": "148", "kind": "constant", "name": "friendlyModelContentType1", "namespace": "", "usage": "None", "valueType": { - "$id": "145", + "$id": "149", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1405,13 +1437,13 @@ "decorators": [] }, { - "$id": "146", + "$id": "150", "kind": "constant", "name": "projectedNameModelContentType", "namespace": "", "usage": "None", "valueType": { - "$id": "147", + "$id": "151", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1421,13 +1453,13 @@ "decorators": [] }, { - "$id": "148", + "$id": "152", "kind": "constant", "name": "projectedNameModelContentType1", "namespace": "", "usage": "None", "valueType": { - "$id": "149", + "$id": "153", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1437,13 +1469,13 @@ "decorators": [] }, { - "$id": "150", + "$id": "154", "kind": "constant", "name": "returnsAnonymousModelContentType", "namespace": "", "usage": "None", "valueType": { - "$id": "151", + "$id": "155", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1453,13 +1485,13 @@ "decorators": [] }, { - "$id": "152", + "$id": "156", "kind": "constant", "name": "internalProtocolContentType", "namespace": "", "usage": "None", "valueType": { - "$id": "153", + "$id": "157", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1469,13 +1501,13 @@ "decorators": [] }, { - "$id": "154", + "$id": "158", "kind": "constant", "name": "internalProtocolContentType1", "namespace": "", "usage": "None", "valueType": { - "$id": "155", + "$id": "159", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1485,13 +1517,13 @@ "decorators": [] }, { - "$id": "156", + "$id": "160", "kind": "constant", "name": "ListWithNextLinkContentType", "namespace": "", "usage": "None", "valueType": { - "$id": "157", + "$id": "161", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1501,13 +1533,13 @@ "decorators": [] }, { - "$id": "158", + "$id": "162", "kind": "constant", "name": "ListWithStringNextLinkContentType", "namespace": "", "usage": "None", "valueType": { - "$id": "159", + "$id": "163", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1517,13 +1549,13 @@ "decorators": [] }, { - "$id": "160", + "$id": "164", "kind": "constant", "name": "ListWithContinuationTokenContentType", "namespace": "", "usage": "None", "valueType": { - "$id": "161", + "$id": "165", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1533,13 +1565,13 @@ "decorators": [] }, { - "$id": "162", + "$id": "166", "kind": "constant", "name": "ListWithContinuationTokenHeaderResponseContentType", "namespace": "", "usage": "None", "valueType": { - "$id": "163", + "$id": "167", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1549,13 +1581,13 @@ "decorators": [] }, { - "$id": "164", + "$id": "168", "kind": "constant", "name": "ListWithPagingContentType", "namespace": "", "usage": "None", "valueType": { - "$id": "165", + "$id": "169", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1565,13 +1597,13 @@ "decorators": [] }, { - "$id": "166", + "$id": "170", "kind": "constant", "name": "EmbeddedParametersContentType", "namespace": "", "usage": "None", "valueType": { - "$id": "167", + "$id": "171", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1581,13 +1613,13 @@ "decorators": [] }, { - "$id": "168", + "$id": "172", "kind": "constant", "name": "DynamicModelOperationContentType", "namespace": "", "usage": "None", "valueType": { - "$id": "169", + "$id": "173", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1597,13 +1629,13 @@ "decorators": [] }, { - "$id": "170", + "$id": "174", "kind": "constant", - "name": "getWidgetMetricsContentType", + "name": "updatePetAsAnimalContentType", "namespace": "", "usage": "None", "valueType": { - "$id": "171", + "$id": "175", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1611,69 +1643,229 @@ }, "value": "application/json", "decorators": [] - } - ], - "models": [ + }, { - "$id": "172", - "kind": "model", - "name": "Thing", - "namespace": "SampleTypeSpec", - "crossLanguageDefinitionId": "SampleTypeSpec.Thing", - "usage": "Input,Output,Spread,Json", - "doc": "A model with a few properties of literal types", - "decorators": [], - "properties": [ - { - "$id": "173", - "kind": "property", - "name": "name", - "serializedName": "name", - "doc": "name of the Thing", - "type": { - "$id": "174", - "kind": "string", - "name": "string", - "crossLanguageDefinitionId": "TypeSpec.string", - "decorators": [] - }, - "optional": false, - "readOnly": false, - "discriminator": false, - "flatten": false, - "decorators": [], - "crossLanguageDefinitionId": "SampleTypeSpec.Thing.name", - "serializationOptions": { - "json": { - "name": "name" - } - }, - "isHttpMetadata": false - }, - { - "$id": "175", - "kind": "property", - "name": "requiredUnion", - "serializedName": "requiredUnion", - "doc": "required Union", - "type": { - "$id": "176", - "kind": "union", - "name": "ThingRequiredUnion", - "variantTypes": [ - { - "$id": "177", - "kind": "string", - "name": "string", - "crossLanguageDefinitionId": "TypeSpec.string", - "decorators": [] - }, + "$id": "176", + "kind": "constant", + "name": "updatePetAsAnimalContentType1", + "namespace": "", + "usage": "None", + "valueType": { + "$id": "177", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "value": "application/json", + "decorators": [] + }, + { + "$id": "178", + "kind": "constant", + "name": "updateDogAsAnimalContentType", + "namespace": "", + "usage": "None", + "valueType": { + "$id": "179", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "value": "application/json", + "decorators": [] + }, + { + "$id": "180", + "kind": "constant", + "name": "updateDogAsAnimalContentType1", + "namespace": "", + "usage": "None", + "valueType": { + "$id": "181", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "value": "application/json", + "decorators": [] + }, + { + "$id": "182", + "kind": "constant", + "name": "updatePetAsPetContentType", + "namespace": "", + "usage": "None", + "valueType": { + "$id": "183", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "value": "application/json", + "decorators": [] + }, + { + "$id": "184", + "kind": "constant", + "name": "updatePetAsPetContentType1", + "namespace": "", + "usage": "None", + "valueType": { + "$id": "185", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "value": "application/json", + "decorators": [] + }, + { + "$id": "186", + "kind": "constant", + "name": "updateDogAsPetContentType", + "namespace": "", + "usage": "None", + "valueType": { + "$id": "187", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "value": "application/json", + "decorators": [] + }, + { + "$id": "188", + "kind": "constant", + "name": "updateDogAsPetContentType1", + "namespace": "", + "usage": "None", + "valueType": { + "$id": "189", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "value": "application/json", + "decorators": [] + }, + { + "$id": "190", + "kind": "constant", + "name": "updateDogAsDogContentType", + "namespace": "", + "usage": "None", + "valueType": { + "$id": "191", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "value": "application/json", + "decorators": [] + }, + { + "$id": "192", + "kind": "constant", + "name": "updateDogAsDogContentType1", + "namespace": "", + "usage": "None", + "valueType": { + "$id": "193", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "value": "application/json", + "decorators": [] + }, + { + "$id": "194", + "kind": "constant", + "name": "getWidgetMetricsContentType", + "namespace": "", + "usage": "None", + "valueType": { + "$id": "195", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "value": "application/json", + "decorators": [] + } + ], + "models": [ + { + "$id": "196", + "kind": "model", + "name": "Thing", + "namespace": "SampleTypeSpec", + "crossLanguageDefinitionId": "SampleTypeSpec.Thing", + "usage": "Input,Output,Spread,Json", + "doc": "A model with a few properties of literal types", + "decorators": [], + "properties": [ + { + "$id": "197", + "kind": "property", + "name": "name", + "serializedName": "name", + "doc": "name of the Thing", + "type": { + "$id": "198", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "optional": false, + "readOnly": false, + "discriminator": false, + "flatten": false, + "decorators": [], + "crossLanguageDefinitionId": "SampleTypeSpec.Thing.name", + "serializationOptions": { + "json": { + "name": "name" + } + }, + "isHttpMetadata": false + }, + { + "$id": "199", + "kind": "property", + "name": "requiredUnion", + "serializedName": "requiredUnion", + "doc": "required Union", + "type": { + "$id": "200", + "kind": "union", + "name": "ThingRequiredUnion", + "variantTypes": [ + { + "$id": "201", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, { - "$id": "178", + "$id": "202", "kind": "array", "name": "Array", "valueType": { - "$id": "179", + "$id": "203", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1683,7 +1875,7 @@ "decorators": [] }, { - "$id": "180", + "$id": "204", "kind": "int32", "name": "int32", "crossLanguageDefinitionId": "TypeSpec.int32", @@ -1707,7 +1899,7 @@ "isHttpMetadata": false }, { - "$id": "181", + "$id": "205", "kind": "property", "name": "requiredLiteralString", "serializedName": "requiredLiteralString", @@ -1729,16 +1921,16 @@ "isHttpMetadata": false }, { - "$id": "182", + "$id": "206", "kind": "property", "name": "requiredNullableString", "serializedName": "requiredNullableString", "doc": "required nullable string", "type": { - "$id": "183", + "$id": "207", "kind": "nullable", "type": { - "$id": "184", + "$id": "208", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1760,16 +1952,16 @@ "isHttpMetadata": false }, { - "$id": "185", + "$id": "209", "kind": "property", "name": "optionalNullableString", "serializedName": "optionalNullableString", "doc": "required optional string", "type": { - "$id": "186", + "$id": "210", "kind": "nullable", "type": { - "$id": "187", + "$id": "211", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1791,7 +1983,7 @@ "isHttpMetadata": false }, { - "$id": "188", + "$id": "212", "kind": "property", "name": "requiredLiteralInt", "serializedName": "requiredLiteralInt", @@ -1813,7 +2005,7 @@ "isHttpMetadata": false }, { - "$id": "189", + "$id": "213", "kind": "property", "name": "requiredLiteralFloat", "serializedName": "requiredLiteralFloat", @@ -1835,7 +2027,7 @@ "isHttpMetadata": false }, { - "$id": "190", + "$id": "214", "kind": "property", "name": "requiredLiteralBool", "serializedName": "requiredLiteralBool", @@ -1857,7 +2049,7 @@ "isHttpMetadata": false }, { - "$id": "191", + "$id": "215", "kind": "property", "name": "optionalLiteralString", "serializedName": "optionalLiteralString", @@ -1879,13 +2071,13 @@ "isHttpMetadata": false }, { - "$id": "192", + "$id": "216", "kind": "property", "name": "requiredNullableLiteralString", "serializedName": "requiredNullableLiteralString", "doc": "required nullable literal string", "type": { - "$id": "193", + "$id": "217", "kind": "nullable", "type": { "$ref": "5" @@ -1906,7 +2098,7 @@ "isHttpMetadata": false }, { - "$id": "194", + "$id": "218", "kind": "property", "name": "optionalLiteralInt", "serializedName": "optionalLiteralInt", @@ -1928,7 +2120,7 @@ "isHttpMetadata": false }, { - "$id": "195", + "$id": "219", "kind": "property", "name": "optionalLiteralFloat", "serializedName": "optionalLiteralFloat", @@ -1950,7 +2142,7 @@ "isHttpMetadata": false }, { - "$id": "196", + "$id": "220", "kind": "property", "name": "optionalLiteralBool", "serializedName": "optionalLiteralBool", @@ -1972,13 +2164,13 @@ "isHttpMetadata": false }, { - "$id": "197", + "$id": "221", "kind": "property", "name": "requiredBadDescription", "serializedName": "requiredBadDescription", "doc": "description with xml <|endoftext|>", "type": { - "$id": "198", + "$id": "222", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1998,20 +2190,20 @@ "isHttpMetadata": false }, { - "$id": "199", + "$id": "223", "kind": "property", "name": "optionalNullableList", "serializedName": "optionalNullableList", "doc": "optional nullable collection", "type": { - "$id": "200", + "$id": "224", "kind": "nullable", "type": { - "$id": "201", + "$id": "225", "kind": "array", "name": "Array1", "valueType": { - "$id": "202", + "$id": "226", "kind": "int32", "name": "int32", "crossLanguageDefinitionId": "TypeSpec.int32", @@ -2036,16 +2228,16 @@ "isHttpMetadata": false }, { - "$id": "203", + "$id": "227", "kind": "property", "name": "requiredNullableList", "serializedName": "requiredNullableList", "doc": "required nullable collection", "type": { - "$id": "204", + "$id": "228", "kind": "nullable", "type": { - "$ref": "201" + "$ref": "225" }, "namespace": "SampleTypeSpec" }, @@ -2065,7 +2257,7 @@ ] }, { - "$id": "205", + "$id": "229", "kind": "model", "name": "RoundTripModel", "namespace": "SampleTypeSpec", @@ -2075,13 +2267,13 @@ "decorators": [], "properties": [ { - "$id": "206", + "$id": "230", "kind": "property", "name": "requiredString", "serializedName": "requiredString", "doc": "Required string, illustrating a reference type property.", "type": { - "$id": "207", + "$id": "231", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -2101,13 +2293,13 @@ "isHttpMetadata": false }, { - "$id": "208", + "$id": "232", "kind": "property", "name": "requiredInt", "serializedName": "requiredInt", "doc": "Required int, illustrating a value type property.", "type": { - "$id": "209", + "$id": "233", "kind": "int32", "name": "int32", "encode": "string", @@ -2128,13 +2320,13 @@ "isHttpMetadata": false }, { - "$id": "210", + "$id": "234", "kind": "property", "name": "requiredCollection", "serializedName": "requiredCollection", "doc": "Required collection of enums", "type": { - "$id": "211", + "$id": "235", "kind": "array", "name": "ArrayStringFixedEnum", "valueType": { @@ -2157,16 +2349,16 @@ "isHttpMetadata": false }, { - "$id": "212", + "$id": "236", "kind": "property", "name": "requiredDictionary", "serializedName": "requiredDictionary", "doc": "Required dictionary of enums", "type": { - "$id": "213", + "$id": "237", "kind": "dict", "keyType": { - "$id": "214", + "$id": "238", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -2191,13 +2383,13 @@ "isHttpMetadata": false }, { - "$id": "215", + "$id": "239", "kind": "property", "name": "requiredModel", "serializedName": "requiredModel", "doc": "Required model", "type": { - "$ref": "172" + "$ref": "196" }, "optional": false, "readOnly": false, @@ -2213,7 +2405,7 @@ "isHttpMetadata": false }, { - "$id": "216", + "$id": "240", "kind": "property", "name": "intExtensibleEnum", "serializedName": "intExtensibleEnum", @@ -2235,13 +2427,13 @@ "isHttpMetadata": false }, { - "$id": "217", + "$id": "241", "kind": "property", "name": "intExtensibleEnumCollection", "serializedName": "intExtensibleEnumCollection", "doc": "this is a collection of int based extensible enum", "type": { - "$id": "218", + "$id": "242", "kind": "array", "name": "ArrayIntExtensibleEnum", "valueType": { @@ -2264,7 +2456,7 @@ "isHttpMetadata": false }, { - "$id": "219", + "$id": "243", "kind": "property", "name": "floatExtensibleEnum", "serializedName": "floatExtensibleEnum", @@ -2286,7 +2478,7 @@ "isHttpMetadata": false }, { - "$id": "220", + "$id": "244", "kind": "property", "name": "floatExtensibleEnumWithIntValue", "serializedName": "floatExtensibleEnumWithIntValue", @@ -2308,13 +2500,13 @@ "isHttpMetadata": false }, { - "$id": "221", + "$id": "245", "kind": "property", "name": "floatExtensibleEnumCollection", "serializedName": "floatExtensibleEnumCollection", "doc": "this is a collection of float based extensible enum", "type": { - "$id": "222", + "$id": "246", "kind": "array", "name": "ArrayFloatExtensibleEnum", "valueType": { @@ -2337,7 +2529,7 @@ "isHttpMetadata": false }, { - "$id": "223", + "$id": "247", "kind": "property", "name": "floatFixedEnum", "serializedName": "floatFixedEnum", @@ -2359,7 +2551,7 @@ "isHttpMetadata": false }, { - "$id": "224", + "$id": "248", "kind": "property", "name": "floatFixedEnumWithIntValue", "serializedName": "floatFixedEnumWithIntValue", @@ -2381,13 +2573,13 @@ "isHttpMetadata": false }, { - "$id": "225", + "$id": "249", "kind": "property", "name": "floatFixedEnumCollection", "serializedName": "floatFixedEnumCollection", "doc": "this is a collection of float based fixed enum", "type": { - "$id": "226", + "$id": "250", "kind": "array", "name": "ArrayFloatFixedEnum", "valueType": { @@ -2410,7 +2602,7 @@ "isHttpMetadata": false }, { - "$id": "227", + "$id": "251", "kind": "property", "name": "intFixedEnum", "serializedName": "intFixedEnum", @@ -2432,13 +2624,13 @@ "isHttpMetadata": false }, { - "$id": "228", + "$id": "252", "kind": "property", "name": "intFixedEnumCollection", "serializedName": "intFixedEnumCollection", "doc": "this is a collection of int based fixed enum", "type": { - "$id": "229", + "$id": "253", "kind": "array", "name": "ArrayIntFixedEnum", "valueType": { @@ -2461,7 +2653,7 @@ "isHttpMetadata": false }, { - "$id": "230", + "$id": "254", "kind": "property", "name": "stringFixedEnum", "serializedName": "stringFixedEnum", @@ -2483,13 +2675,13 @@ "isHttpMetadata": false }, { - "$id": "231", + "$id": "255", "kind": "property", "name": "requiredUnknown", "serializedName": "requiredUnknown", "doc": "required unknown", "type": { - "$id": "232", + "$id": "256", "kind": "unknown", "name": "unknown", "crossLanguageDefinitionId": "", @@ -2509,13 +2701,13 @@ "isHttpMetadata": false }, { - "$id": "233", + "$id": "257", "kind": "property", "name": "optionalUnknown", "serializedName": "optionalUnknown", "doc": "optional unknown", "type": { - "$id": "234", + "$id": "258", "kind": "unknown", "name": "unknown", "crossLanguageDefinitionId": "", @@ -2535,23 +2727,23 @@ "isHttpMetadata": false }, { - "$id": "235", + "$id": "259", "kind": "property", "name": "requiredRecordUnknown", "serializedName": "requiredRecordUnknown", "doc": "required record of unknown", "type": { - "$id": "236", + "$id": "260", "kind": "dict", "keyType": { - "$id": "237", + "$id": "261", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", "decorators": [] }, "valueType": { - "$id": "238", + "$id": "262", "kind": "unknown", "name": "unknown", "crossLanguageDefinitionId": "", @@ -2573,13 +2765,13 @@ "isHttpMetadata": false }, { - "$id": "239", + "$id": "263", "kind": "property", "name": "optionalRecordUnknown", "serializedName": "optionalRecordUnknown", "doc": "optional record of unknown", "type": { - "$ref": "236" + "$ref": "260" }, "optional": true, "readOnly": false, @@ -2595,13 +2787,13 @@ "isHttpMetadata": false }, { - "$id": "240", + "$id": "264", "kind": "property", "name": "readOnlyRequiredRecordUnknown", "serializedName": "readOnlyRequiredRecordUnknown", "doc": "required readonly record of unknown", "type": { - "$ref": "236" + "$ref": "260" }, "optional": false, "readOnly": true, @@ -2617,13 +2809,13 @@ "isHttpMetadata": false }, { - "$id": "241", + "$id": "265", "kind": "property", "name": "readOnlyOptionalRecordUnknown", "serializedName": "readOnlyOptionalRecordUnknown", "doc": "optional readonly record of unknown", "type": { - "$ref": "236" + "$ref": "260" }, "optional": true, "readOnly": true, @@ -2639,13 +2831,13 @@ "isHttpMetadata": false }, { - "$id": "242", + "$id": "266", "kind": "property", "name": "modelWithRequiredNullable", "serializedName": "modelWithRequiredNullable", "doc": "this is a model with required nullable properties", "type": { - "$id": "243", + "$id": "267", "kind": "model", "name": "ModelWithRequiredNullableProperties", "namespace": "SampleTypeSpec", @@ -2655,16 +2847,16 @@ "decorators": [], "properties": [ { - "$id": "244", + "$id": "268", "kind": "property", "name": "requiredNullablePrimitive", "serializedName": "requiredNullablePrimitive", "doc": "required nullable primitive type", "type": { - "$id": "245", + "$id": "269", "kind": "nullable", "type": { - "$id": "246", + "$id": "270", "kind": "int32", "name": "int32", "crossLanguageDefinitionId": "TypeSpec.int32", @@ -2686,13 +2878,13 @@ "isHttpMetadata": false }, { - "$id": "247", + "$id": "271", "kind": "property", "name": "requiredExtensibleEnum", "serializedName": "requiredExtensibleEnum", "doc": "required nullable extensible enum type", "type": { - "$id": "248", + "$id": "272", "kind": "nullable", "type": { "$ref": "22" @@ -2713,13 +2905,13 @@ "isHttpMetadata": false }, { - "$id": "249", + "$id": "273", "kind": "property", "name": "requiredFixedEnum", "serializedName": "requiredFixedEnum", "doc": "required nullable fixed enum type", "type": { - "$id": "250", + "$id": "274", "kind": "nullable", "type": { "$ref": "17" @@ -2755,13 +2947,13 @@ "isHttpMetadata": false }, { - "$id": "251", + "$id": "275", "kind": "property", "name": "requiredBytes", "serializedName": "requiredBytes", "doc": "Required bytes", "type": { - "$id": "252", + "$id": "276", "kind": "bytes", "name": "bytes", "encode": "base64", @@ -2784,10 +2976,10 @@ ] }, { - "$ref": "243" + "$ref": "267" }, { - "$id": "253", + "$id": "277", "kind": "model", "name": "Friend", "namespace": "SampleTypeSpec", @@ -2797,13 +2989,13 @@ "decorators": [], "properties": [ { - "$id": "254", + "$id": "278", "kind": "property", "name": "name", "serializedName": "name", "doc": "name of the NotFriend", "type": { - "$id": "255", + "$id": "279", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -2825,7 +3017,7 @@ ] }, { - "$id": "256", + "$id": "280", "kind": "model", "name": "RenamedModel", "namespace": "SampleTypeSpec", @@ -2835,13 +3027,13 @@ "decorators": [], "properties": [ { - "$id": "257", + "$id": "281", "kind": "property", "name": "otherName", "serializedName": "otherName", "doc": "name of the ModelWithClientName", "type": { - "$id": "258", + "$id": "282", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -2863,7 +3055,7 @@ ] }, { - "$id": "259", + "$id": "283", "kind": "model", "name": "ReturnsAnonymousModelResponse", "namespace": "SampleTypeSpec", @@ -2873,7 +3065,7 @@ "properties": [] }, { - "$id": "260", + "$id": "284", "kind": "model", "name": "ListWithNextLinkResponse", "namespace": "SampleTypeSpec", @@ -2882,16 +3074,16 @@ "decorators": [], "properties": [ { - "$id": "261", + "$id": "285", "kind": "property", "name": "things", "serializedName": "things", "type": { - "$id": "262", + "$id": "286", "kind": "array", "name": "ArrayThing", "valueType": { - "$ref": "172" + "$ref": "196" }, "crossLanguageDefinitionId": "TypeSpec.Array", "decorators": [] @@ -2910,12 +3102,12 @@ "isHttpMetadata": false }, { - "$id": "263", + "$id": "287", "kind": "property", "name": "next", "serializedName": "next", "type": { - "$id": "264", + "$id": "288", "kind": "url", "name": "url", "crossLanguageDefinitionId": "TypeSpec.url", @@ -2937,7 +3129,7 @@ ] }, { - "$id": "265", + "$id": "289", "kind": "model", "name": "ListWithStringNextLinkResponse", "namespace": "SampleTypeSpec", @@ -2946,12 +3138,12 @@ "decorators": [], "properties": [ { - "$id": "266", + "$id": "290", "kind": "property", "name": "things", "serializedName": "things", "type": { - "$ref": "262" + "$ref": "286" }, "optional": false, "readOnly": false, @@ -2967,12 +3159,12 @@ "isHttpMetadata": false }, { - "$id": "267", + "$id": "291", "kind": "property", "name": "next", "serializedName": "next", "type": { - "$id": "268", + "$id": "292", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -2994,7 +3186,7 @@ ] }, { - "$id": "269", + "$id": "293", "kind": "model", "name": "ListWithContinuationTokenResponse", "namespace": "SampleTypeSpec", @@ -3003,12 +3195,12 @@ "decorators": [], "properties": [ { - "$id": "270", + "$id": "294", "kind": "property", "name": "things", "serializedName": "things", "type": { - "$ref": "262" + "$ref": "286" }, "optional": false, "readOnly": false, @@ -3024,12 +3216,12 @@ "isHttpMetadata": false }, { - "$id": "271", + "$id": "295", "kind": "property", "name": "nextToken", "serializedName": "nextToken", "type": { - "$id": "272", + "$id": "296", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -3051,7 +3243,7 @@ ] }, { - "$id": "273", + "$id": "297", "kind": "model", "name": "ListWithContinuationTokenHeaderResponseResponse", "namespace": "", @@ -3060,12 +3252,12 @@ "decorators": [], "properties": [ { - "$id": "274", + "$id": "298", "kind": "property", "name": "things", "serializedName": "things", "type": { - "$ref": "262" + "$ref": "286" }, "optional": false, "readOnly": false, @@ -3083,7 +3275,7 @@ ] }, { - "$id": "275", + "$id": "299", "kind": "model", "name": "PageThing", "namespace": "SampleTypeSpec", @@ -3092,12 +3284,12 @@ "decorators": [], "properties": [ { - "$id": "276", + "$id": "300", "kind": "property", "name": "items", "serializedName": "items", "type": { - "$ref": "262" + "$ref": "286" }, "optional": false, "readOnly": false, @@ -3115,7 +3307,7 @@ ] }, { - "$id": "277", + "$id": "301", "kind": "model", "name": "ModelWithEmbeddedNonBodyParameters", "namespace": "SampleTypeSpec", @@ -3124,13 +3316,13 @@ "decorators": [], "properties": [ { - "$id": "278", + "$id": "302", "kind": "property", "name": "name", "serializedName": "name", "doc": "name of the ModelWithEmbeddedNonBodyParameters", "type": { - "$id": "279", + "$id": "303", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -3150,13 +3342,13 @@ "isHttpMetadata": false }, { - "$id": "280", + "$id": "304", "kind": "property", "name": "requiredHeader", "serializedName": "requiredHeader", "doc": "required header parameter", "type": { - "$id": "281", + "$id": "305", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -3176,13 +3368,13 @@ "isHttpMetadata": true }, { - "$id": "282", + "$id": "306", "kind": "property", "name": "optionalHeader", "serializedName": "optionalHeader", "doc": "optional header parameter", "type": { - "$id": "283", + "$id": "307", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -3202,13 +3394,13 @@ "isHttpMetadata": true }, { - "$id": "284", + "$id": "308", "kind": "property", "name": "requiredQuery", "serializedName": "requiredQuery", "doc": "required query parameter", "type": { - "$id": "285", + "$id": "309", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -3228,13 +3420,13 @@ "isHttpMetadata": true }, { - "$id": "286", + "$id": "310", "kind": "property", "name": "optionalQuery", "serializedName": "optionalQuery", "doc": "optional query parameter", "type": { - "$id": "287", + "$id": "311", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -3256,7 +3448,7 @@ ] }, { - "$id": "288", + "$id": "312", "kind": "model", "name": "DynamicModel", "namespace": "SampleTypeSpec", @@ -3271,12 +3463,12 @@ ], "properties": [ { - "$id": "289", + "$id": "313", "kind": "property", "name": "name", "serializedName": "name", "type": { - "$id": "290", + "$id": "314", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -3296,12 +3488,12 @@ "isHttpMetadata": false }, { - "$id": "291", + "$id": "315", "kind": "property", "name": "optionalUnknown", "serializedName": "optionalUnknown", "type": { - "$id": "292", + "$id": "316", "kind": "unknown", "name": "unknown", "crossLanguageDefinitionId": "", @@ -3321,12 +3513,12 @@ "isHttpMetadata": false }, { - "$id": "293", + "$id": "317", "kind": "property", "name": "optionalInt", "serializedName": "optionalInt", "type": { - "$id": "294", + "$id": "318", "kind": "int32", "name": "int32", "crossLanguageDefinitionId": "TypeSpec.int32", @@ -3346,15 +3538,15 @@ "isHttpMetadata": false }, { - "$id": "295", + "$id": "319", "kind": "property", "name": "optionalNullableList", "serializedName": "optionalNullableList", "type": { - "$id": "296", + "$id": "320", "kind": "nullable", "type": { - "$ref": "201" + "$ref": "225" }, "namespace": "SampleTypeSpec" }, @@ -3372,15 +3564,15 @@ "isHttpMetadata": false }, { - "$id": "297", + "$id": "321", "kind": "property", "name": "requiredNullableList", "serializedName": "requiredNullableList", "type": { - "$id": "298", + "$id": "322", "kind": "nullable", "type": { - "$ref": "201" + "$ref": "225" }, "namespace": "SampleTypeSpec" }, @@ -3398,25 +3590,25 @@ "isHttpMetadata": false }, { - "$id": "299", + "$id": "323", "kind": "property", "name": "optionalNullableDictionary", "serializedName": "optionalNullableDictionary", "type": { - "$id": "300", + "$id": "324", "kind": "nullable", "type": { - "$id": "301", + "$id": "325", "kind": "dict", "keyType": { - "$id": "302", + "$id": "326", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", "decorators": [] }, "valueType": { - "$id": "303", + "$id": "327", "kind": "int32", "name": "int32", "crossLanguageDefinitionId": "TypeSpec.int32", @@ -3440,15 +3632,15 @@ "isHttpMetadata": false }, { - "$id": "304", + "$id": "328", "kind": "property", "name": "requiredNullableDictionary", "serializedName": "requiredNullableDictionary", "type": { - "$id": "305", + "$id": "329", "kind": "nullable", "type": { - "$ref": "301" + "$ref": "325" }, "namespace": "SampleTypeSpec" }, @@ -3466,12 +3658,12 @@ "isHttpMetadata": false }, { - "$id": "306", + "$id": "330", "kind": "property", "name": "primitiveDictionary", "serializedName": "primitiveDictionary", "type": { - "$ref": "301" + "$ref": "325" }, "optional": false, "readOnly": false, @@ -3487,12 +3679,12 @@ "isHttpMetadata": false }, { - "$id": "307", + "$id": "331", "kind": "property", "name": "foo", "serializedName": "foo", "type": { - "$id": "308", + "$id": "332", "kind": "model", "name": "AnotherDynamicModel", "namespace": "SampleTypeSpec", @@ -3507,12 +3699,12 @@ ], "properties": [ { - "$id": "309", + "$id": "333", "kind": "property", "name": "bar", "serializedName": "bar", "type": { - "$id": "310", + "$id": "334", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -3547,16 +3739,16 @@ "isHttpMetadata": false }, { - "$id": "311", + "$id": "335", "kind": "property", "name": "listFoo", "serializedName": "listFoo", "type": { - "$id": "312", + "$id": "336", "kind": "array", "name": "ArrayAnotherDynamicModel", "valueType": { - "$ref": "308" + "$ref": "332" }, "crossLanguageDefinitionId": "TypeSpec.Array", "decorators": [] @@ -3575,16 +3767,16 @@ "isHttpMetadata": false }, { - "$id": "313", + "$id": "337", "kind": "property", "name": "listOfListFoo", "serializedName": "listOfListFoo", "type": { - "$id": "314", + "$id": "338", "kind": "array", "name": "ArrayArray", "valueType": { - "$ref": "312" + "$ref": "336" }, "crossLanguageDefinitionId": "TypeSpec.Array", "decorators": [] @@ -3603,22 +3795,22 @@ "isHttpMetadata": false }, { - "$id": "315", + "$id": "339", "kind": "property", "name": "dictionaryFoo", "serializedName": "dictionaryFoo", "type": { - "$id": "316", + "$id": "340", "kind": "dict", "keyType": { - "$id": "317", + "$id": "341", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", "decorators": [] }, "valueType": { - "$ref": "308" + "$ref": "332" }, "decorators": [] }, @@ -3636,22 +3828,22 @@ "isHttpMetadata": false }, { - "$id": "318", + "$id": "342", "kind": "property", "name": "dictionaryOfDictionaryFoo", "serializedName": "dictionaryOfDictionaryFoo", "type": { - "$id": "319", + "$id": "343", "kind": "dict", "keyType": { - "$id": "320", + "$id": "344", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", "decorators": [] }, "valueType": { - "$ref": "316" + "$ref": "340" }, "decorators": [] }, @@ -3669,22 +3861,22 @@ "isHttpMetadata": false }, { - "$id": "321", + "$id": "345", "kind": "property", "name": "dictionaryListFoo", "serializedName": "dictionaryListFoo", "type": { - "$id": "322", + "$id": "346", "kind": "dict", "keyType": { - "$id": "323", + "$id": "347", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", "decorators": [] }, "valueType": { - "$ref": "312" + "$ref": "336" }, "decorators": [] }, @@ -3702,16 +3894,16 @@ "isHttpMetadata": false }, { - "$id": "324", + "$id": "348", "kind": "property", "name": "listOfDictionaryFoo", "serializedName": "listOfDictionaryFoo", "type": { - "$id": "325", + "$id": "349", "kind": "array", "name": "ArrayRecord", "valueType": { - "$ref": "316" + "$ref": "340" }, "crossLanguageDefinitionId": "TypeSpec.Array", "decorators": [] @@ -3732,10 +3924,219 @@ ] }, { - "$ref": "308" + "$ref": "332" + }, + { + "$id": "350", + "kind": "model", + "name": "Animal", + "namespace": "SampleTypeSpec", + "crossLanguageDefinitionId": "SampleTypeSpec.Animal", + "usage": "Input,Output,Json", + "doc": "Base animal with discriminator", + "decorators": [], + "discriminatorProperty": { + "$id": "351", + "kind": "property", + "name": "kind", + "serializedName": "kind", + "doc": "The kind of animal", + "type": { + "$id": "352", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "optional": false, + "readOnly": false, + "discriminator": true, + "flatten": false, + "decorators": [], + "crossLanguageDefinitionId": "SampleTypeSpec.Animal.kind", + "serializationOptions": { + "json": { + "name": "kind" + } + }, + "isHttpMetadata": false + }, + "properties": [ + { + "$ref": "351" + }, + { + "$id": "353", + "kind": "property", + "name": "name", + "serializedName": "name", + "doc": "Name of the animal", + "type": { + "$id": "354", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "optional": false, + "readOnly": false, + "discriminator": false, + "flatten": false, + "decorators": [], + "crossLanguageDefinitionId": "SampleTypeSpec.Animal.name", + "serializationOptions": { + "json": { + "name": "name" + } + }, + "isHttpMetadata": false + } + ], + "discriminatedSubtypes": { + "pet": { + "$id": "355", + "kind": "model", + "name": "Pet", + "namespace": "SampleTypeSpec", + "crossLanguageDefinitionId": "SampleTypeSpec.Pet", + "usage": "Input,Output,Json", + "doc": "Pet is a discriminated animal", + "discriminatorValue": "pet", + "decorators": [], + "discriminatorProperty": { + "$id": "356", + "kind": "property", + "name": "kind", + "serializedName": "kind", + "type": { + "$ref": "80" + }, + "optional": false, + "readOnly": false, + "discriminator": true, + "flatten": false, + "decorators": [], + "crossLanguageDefinitionId": "SampleTypeSpec.Pet.kind", + "serializationOptions": { + "json": { + "name": "kind" + } + }, + "isHttpMetadata": false + }, + "baseModel": { + "$ref": "350" + }, + "properties": [ + { + "$ref": "356" + }, + { + "$id": "357", + "kind": "property", + "name": "trained", + "serializedName": "trained", + "doc": "Whether the pet is trained", + "type": { + "$id": "358", + "kind": "boolean", + "name": "boolean", + "crossLanguageDefinitionId": "TypeSpec.boolean", + "decorators": [] + }, + "optional": false, + "readOnly": false, + "discriminator": false, + "flatten": false, + "decorators": [], + "crossLanguageDefinitionId": "SampleTypeSpec.Pet.trained", + "serializationOptions": { + "json": { + "name": "trained" + } + }, + "isHttpMetadata": false + } + ], + "discriminatedSubtypes": { + "dog": { + "$id": "359", + "kind": "model", + "name": "Dog", + "namespace": "SampleTypeSpec", + "crossLanguageDefinitionId": "SampleTypeSpec.Dog", + "usage": "Input,Output,Json", + "doc": "Dog is a specific type of pet with hierarchy building", + "discriminatorValue": "dog", + "decorators": [], + "baseModel": { + "$ref": "355" + }, + "properties": [ + { + "$id": "360", + "kind": "property", + "name": "kind", + "serializedName": "kind", + "type": { + "$ref": "82" + }, + "optional": false, + "readOnly": false, + "discriminator": true, + "flatten": false, + "decorators": [], + "crossLanguageDefinitionId": "SampleTypeSpec.Dog.kind", + "serializationOptions": { + "json": { + "name": "kind" + } + }, + "isHttpMetadata": false + }, + { + "$id": "361", + "kind": "property", + "name": "breed", + "serializedName": "breed", + "doc": "The breed of the dog", + "type": { + "$id": "362", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "optional": false, + "readOnly": false, + "discriminator": false, + "flatten": false, + "decorators": [], + "crossLanguageDefinitionId": "SampleTypeSpec.Dog.breed", + "serializationOptions": { + "json": { + "name": "breed" + } + }, + "isHttpMetadata": false + } + ] + } + } + }, + "dog": { + "$ref": "359" + } + } + }, + { + "$ref": "355" + }, + { + "$ref": "359" }, { - "$id": "326", + "$id": "363", "kind": "model", "name": "GetWidgetMetricsResponse", "namespace": "SampleTypeSpec", @@ -3744,12 +4145,12 @@ "decorators": [], "properties": [ { - "$id": "327", + "$id": "364", "kind": "property", "name": "numSold", "serializedName": "numSold", "type": { - "$id": "328", + "$id": "365", "kind": "int32", "name": "int32", "crossLanguageDefinitionId": "TypeSpec.int32", @@ -3769,12 +4170,12 @@ "isHttpMetadata": false }, { - "$id": "329", + "$id": "366", "kind": "property", "name": "averagePrice", "serializedName": "averagePrice", "type": { - "$id": "330", + "$id": "367", "kind": "float32", "name": "float32", "crossLanguageDefinitionId": "TypeSpec.float32", @@ -3798,14 +4199,14 @@ ], "clients": [ { - "$id": "331", + "$id": "368", "kind": "client", "name": "SampleTypeSpecClient", "namespace": "SampleTypeSpec", "doc": "This is a sample typespec project.", "methods": [ { - "$id": "332", + "$id": "369", "kind": "basic", "name": "sayHi", "accessibility": "public", @@ -3815,19 +4216,19 @@ ], "doc": "Return hi", "operation": { - "$id": "333", + "$id": "370", "name": "sayHi", "resourceName": "SampleTypeSpec", "doc": "Return hi", "accessibility": "public", "parameters": [ { - "$id": "334", + "$id": "371", "kind": "header", "name": "headParameter", "serializedName": "head-parameter", "type": { - "$id": "335", + "$id": "372", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -3842,12 +4243,12 @@ "crossLanguageDefinitionId": "SampleTypeSpec.sayHi.headParameter" }, { - "$id": "336", + "$id": "373", "kind": "query", "name": "queryParameter", "serializedName": "queryParameter", "type": { - "$id": "337", + "$id": "374", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -3862,12 +4263,12 @@ "readOnly": false }, { - "$id": "338", + "$id": "375", "kind": "query", "name": "optionalQuery", "serializedName": "optionalQuery", "type": { - "$id": "339", + "$id": "376", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -3882,12 +4283,12 @@ "readOnly": false }, { - "$id": "340", + "$id": "377", "kind": "header", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "80" + "$ref": "84" }, "isApiVersion": false, "optional": false, @@ -3904,7 +4305,7 @@ 200 ], "bodyType": { - "$ref": "172" + "$ref": "196" }, "headers": [], "isErrorResponse": false, @@ -3924,12 +4325,12 @@ }, "parameters": [ { - "$id": "341", + "$id": "378", "kind": "method", "name": "headParameter", "serializedName": "head-parameter", "type": { - "$id": "342", + "$id": "379", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -3945,12 +4346,12 @@ "decorators": [] }, { - "$id": "343", + "$id": "380", "kind": "method", "name": "queryParameter", "serializedName": "queryParameter", "type": { - "$id": "344", + "$id": "381", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -3966,12 +4367,12 @@ "decorators": [] }, { - "$id": "345", + "$id": "382", "kind": "method", "name": "optionalQuery", "serializedName": "optionalQuery", "type": { - "$id": "346", + "$id": "383", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -3987,12 +4388,12 @@ "decorators": [] }, { - "$id": "347", + "$id": "384", "kind": "method", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "80" + "$ref": "84" }, "location": "Header", "isApiVersion": false, @@ -4006,7 +4407,7 @@ ], "response": { "type": { - "$ref": "172" + "$ref": "196" } }, "isOverride": false, @@ -4015,7 +4416,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.sayHi" }, { - "$id": "348", + "$id": "385", "kind": "basic", "name": "helloAgain", "accessibility": "public", @@ -4025,19 +4426,19 @@ ], "doc": "Return hi again", "operation": { - "$id": "349", + "$id": "386", "name": "helloAgain", "resourceName": "SampleTypeSpec", "doc": "Return hi again", "accessibility": "public", "parameters": [ { - "$id": "350", + "$id": "387", "kind": "header", "name": "p1", "serializedName": "p1", "type": { - "$id": "351", + "$id": "388", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -4052,12 +4453,12 @@ "crossLanguageDefinitionId": "SampleTypeSpec.helloAgain.p1" }, { - "$id": "352", + "$id": "389", "kind": "header", "name": "contentType", "serializedName": "Content-Type", "type": { - "$ref": "82" + "$ref": "86" }, "isApiVersion": false, "optional": false, @@ -4068,12 +4469,12 @@ "crossLanguageDefinitionId": "SampleTypeSpec.helloAgain.contentType" }, { - "$id": "353", + "$id": "390", "kind": "path", "name": "p2", "serializedName": "p2", "type": { - "$id": "354", + "$id": "391", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -4091,12 +4492,12 @@ "crossLanguageDefinitionId": "SampleTypeSpec.helloAgain.p2" }, { - "$id": "355", + "$id": "392", "kind": "header", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "84" + "$ref": "88" }, "isApiVersion": false, "optional": false, @@ -4107,12 +4508,12 @@ "crossLanguageDefinitionId": "SampleTypeSpec.helloAgain.accept" }, { - "$id": "356", + "$id": "393", "kind": "body", "name": "action", "serializedName": "action", "type": { - "$ref": "205" + "$ref": "229" }, "isApiVersion": false, "contentTypes": [ @@ -4132,7 +4533,7 @@ 200 ], "bodyType": { - "$ref": "205" + "$ref": "229" }, "headers": [], "isErrorResponse": false, @@ -4155,12 +4556,12 @@ }, "parameters": [ { - "$id": "357", + "$id": "394", "kind": "method", "name": "p1", "serializedName": "p1", "type": { - "$id": "358", + "$id": "395", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -4176,12 +4577,12 @@ "decorators": [] }, { - "$id": "359", + "$id": "396", "kind": "method", "name": "action", "serializedName": "action", "type": { - "$ref": "205" + "$ref": "229" }, "location": "Body", "isApiVersion": false, @@ -4193,12 +4594,12 @@ "decorators": [] }, { - "$id": "360", + "$id": "397", "kind": "method", "name": "contentType", "serializedName": "Content-Type", "type": { - "$ref": "86" + "$ref": "90" }, "location": "Header", "isApiVersion": false, @@ -4210,12 +4611,12 @@ "decorators": [] }, { - "$id": "361", + "$id": "398", "kind": "method", "name": "p2", "serializedName": "p2", "type": { - "$id": "362", + "$id": "399", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -4231,12 +4632,12 @@ "decorators": [] }, { - "$id": "363", + "$id": "400", "kind": "method", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "84" + "$ref": "88" }, "location": "Header", "isApiVersion": false, @@ -4250,7 +4651,7 @@ ], "response": { "type": { - "$ref": "205" + "$ref": "229" } }, "isOverride": false, @@ -4259,7 +4660,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.helloAgain" }, { - "$id": "364", + "$id": "401", "kind": "basic", "name": "noContentType", "accessibility": "public", @@ -4269,19 +4670,19 @@ ], "doc": "Return hi again", "operation": { - "$id": "365", + "$id": "402", "name": "noContentType", "resourceName": "SampleTypeSpec", "doc": "Return hi again", "accessibility": "public", "parameters": [ { - "$id": "366", + "$id": "403", "kind": "header", "name": "p1", "serializedName": "p1", "type": { - "$id": "367", + "$id": "404", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -4296,12 +4697,12 @@ "crossLanguageDefinitionId": "SampleTypeSpec.noContentType.p1" }, { - "$id": "368", + "$id": "405", "kind": "path", "name": "p2", "serializedName": "p2", "type": { - "$id": "369", + "$id": "406", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -4319,13 +4720,13 @@ "crossLanguageDefinitionId": "SampleTypeSpec.noContentType.p2" }, { - "$id": "370", + "$id": "407", "kind": "header", "name": "contentType", "serializedName": "Content-Type", "doc": "Body parameter's content type. Known values are application/json", "type": { - "$ref": "88" + "$ref": "92" }, "isApiVersion": false, "optional": false, @@ -4336,12 +4737,12 @@ "crossLanguageDefinitionId": "SampleTypeSpec.noContentType.contentType" }, { - "$id": "371", + "$id": "408", "kind": "header", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "90" + "$ref": "94" }, "isApiVersion": false, "optional": false, @@ -4352,12 +4753,12 @@ "crossLanguageDefinitionId": "SampleTypeSpec.noContentType.accept" }, { - "$id": "372", + "$id": "409", "kind": "body", "name": "action", "serializedName": "action", "type": { - "$ref": "205" + "$ref": "229" }, "isApiVersion": false, "contentTypes": [ @@ -4377,7 +4778,7 @@ 200 ], "bodyType": { - "$ref": "205" + "$ref": "229" }, "headers": [], "isErrorResponse": false, @@ -4400,12 +4801,12 @@ }, "parameters": [ { - "$id": "373", + "$id": "410", "kind": "method", "name": "p1", "serializedName": "p1", "type": { - "$id": "374", + "$id": "411", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -4421,12 +4822,12 @@ "decorators": [] }, { - "$id": "375", + "$id": "412", "kind": "method", "name": "action", "serializedName": "action", "type": { - "$ref": "205" + "$ref": "229" }, "location": "Body", "isApiVersion": false, @@ -4438,12 +4839,12 @@ "decorators": [] }, { - "$id": "376", + "$id": "413", "kind": "method", "name": "p2", "serializedName": "p2", "type": { - "$id": "377", + "$id": "414", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -4459,13 +4860,13 @@ "decorators": [] }, { - "$id": "378", + "$id": "415", "kind": "method", "name": "contentType", "serializedName": "Content-Type", "doc": "Body parameter's content type. Known values are application/json", "type": { - "$ref": "88" + "$ref": "92" }, "location": "Header", "isApiVersion": false, @@ -4477,12 +4878,12 @@ "decorators": [] }, { - "$id": "379", + "$id": "416", "kind": "method", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "90" + "$ref": "94" }, "location": "Header", "isApiVersion": false, @@ -4496,7 +4897,7 @@ ], "response": { "type": { - "$ref": "205" + "$ref": "229" } }, "isOverride": false, @@ -4505,7 +4906,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.noContentType" }, { - "$id": "380", + "$id": "417", "kind": "basic", "name": "helloDemo2", "accessibility": "public", @@ -4515,19 +4916,19 @@ ], "doc": "Return hi in demo2", "operation": { - "$id": "381", + "$id": "418", "name": "helloDemo2", "resourceName": "SampleTypeSpec", "doc": "Return hi in demo2", "accessibility": "public", "parameters": [ { - "$id": "382", + "$id": "419", "kind": "header", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "92" + "$ref": "96" }, "isApiVersion": false, "optional": false, @@ -4544,7 +4945,7 @@ 200 ], "bodyType": { - "$ref": "172" + "$ref": "196" }, "headers": [], "isErrorResponse": false, @@ -4564,12 +4965,12 @@ }, "parameters": [ { - "$id": "383", + "$id": "420", "kind": "method", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "92" + "$ref": "96" }, "location": "Header", "isApiVersion": false, @@ -4583,7 +4984,7 @@ ], "response": { "type": { - "$ref": "172" + "$ref": "196" } }, "isOverride": false, @@ -4592,7 +4993,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.helloDemo2" }, { - "$id": "384", + "$id": "421", "kind": "basic", "name": "createLiteral", "accessibility": "public", @@ -4602,20 +5003,20 @@ ], "doc": "Create with literal value", "operation": { - "$id": "385", + "$id": "422", "name": "createLiteral", "resourceName": "SampleTypeSpec", "doc": "Create with literal value", "accessibility": "public", "parameters": [ { - "$id": "386", + "$id": "423", "kind": "header", "name": "contentType", "serializedName": "Content-Type", "doc": "Body parameter's content type. Known values are application/json", "type": { - "$ref": "94" + "$ref": "98" }, "isApiVersion": false, "optional": false, @@ -4626,12 +5027,12 @@ "crossLanguageDefinitionId": "SampleTypeSpec.createLiteral.contentType" }, { - "$id": "387", + "$id": "424", "kind": "header", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "96" + "$ref": "100" }, "isApiVersion": false, "optional": false, @@ -4642,12 +5043,12 @@ "crossLanguageDefinitionId": "SampleTypeSpec.createLiteral.accept" }, { - "$id": "388", + "$id": "425", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$ref": "172" + "$ref": "196" }, "isApiVersion": false, "contentTypes": [ @@ -4667,7 +5068,7 @@ 200 ], "bodyType": { - "$ref": "172" + "$ref": "196" }, "headers": [], "isErrorResponse": false, @@ -4690,12 +5091,12 @@ }, "parameters": [ { - "$id": "389", + "$id": "426", "kind": "method", "name": "body", "serializedName": "body", "type": { - "$ref": "172" + "$ref": "196" }, "location": "Body", "isApiVersion": false, @@ -4707,13 +5108,13 @@ "decorators": [] }, { - "$id": "390", + "$id": "427", "kind": "method", "name": "contentType", "serializedName": "Content-Type", "doc": "Body parameter's content type. Known values are application/json", "type": { - "$ref": "94" + "$ref": "98" }, "location": "Header", "isApiVersion": false, @@ -4725,12 +5126,12 @@ "decorators": [] }, { - "$id": "391", + "$id": "428", "kind": "method", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "96" + "$ref": "100" }, "location": "Header", "isApiVersion": false, @@ -4744,7 +5145,7 @@ ], "response": { "type": { - "$ref": "172" + "$ref": "196" } }, "isOverride": false, @@ -4753,7 +5154,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.createLiteral" }, { - "$id": "392", + "$id": "429", "kind": "basic", "name": "helloLiteral", "accessibility": "public", @@ -4763,19 +5164,19 @@ ], "doc": "Send literal parameters", "operation": { - "$id": "393", + "$id": "430", "name": "helloLiteral", "resourceName": "SampleTypeSpec", "doc": "Send literal parameters", "accessibility": "public", "parameters": [ { - "$id": "394", + "$id": "431", "kind": "header", "name": "p1", "serializedName": "p1", "type": { - "$ref": "98" + "$ref": "102" }, "isApiVersion": false, "optional": false, @@ -4786,12 +5187,12 @@ "crossLanguageDefinitionId": "SampleTypeSpec.helloLiteral.p1" }, { - "$id": "395", + "$id": "432", "kind": "path", "name": "p2", "serializedName": "p2", "type": { - "$ref": "100" + "$ref": "104" }, "isApiVersion": false, "explode": false, @@ -4805,12 +5206,12 @@ "crossLanguageDefinitionId": "SampleTypeSpec.helloLiteral.p2" }, { - "$id": "396", + "$id": "433", "kind": "query", "name": "p3", "serializedName": "p3", "type": { - "$ref": "102" + "$ref": "106" }, "isApiVersion": false, "explode": false, @@ -4821,12 +5222,12 @@ "readOnly": false }, { - "$id": "397", + "$id": "434", "kind": "header", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "104" + "$ref": "108" }, "isApiVersion": false, "optional": false, @@ -4843,7 +5244,7 @@ 200 ], "bodyType": { - "$ref": "172" + "$ref": "196" }, "headers": [], "isErrorResponse": false, @@ -4863,12 +5264,12 @@ }, "parameters": [ { - "$id": "398", + "$id": "435", "kind": "method", "name": "p1", "serializedName": "p1", "type": { - "$ref": "106" + "$ref": "110" }, "location": "Header", "isApiVersion": false, @@ -4880,12 +5281,12 @@ "decorators": [] }, { - "$id": "399", + "$id": "436", "kind": "method", "name": "p2", "serializedName": "p2", "type": { - "$ref": "108" + "$ref": "112" }, "location": "Path", "isApiVersion": false, @@ -4897,12 +5298,12 @@ "decorators": [] }, { - "$id": "400", + "$id": "437", "kind": "method", "name": "p3", "serializedName": "p3", "type": { - "$ref": "110" + "$ref": "114" }, "location": "Query", "isApiVersion": false, @@ -4914,12 +5315,12 @@ "decorators": [] }, { - "$id": "401", + "$id": "438", "kind": "method", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "104" + "$ref": "108" }, "location": "Header", "isApiVersion": false, @@ -4933,7 +5334,7 @@ ], "response": { "type": { - "$ref": "172" + "$ref": "196" } }, "isOverride": false, @@ -4942,7 +5343,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.helloLiteral" }, { - "$id": "402", + "$id": "439", "kind": "basic", "name": "topAction", "accessibility": "public", @@ -4952,24 +5353,24 @@ ], "doc": "top level method", "operation": { - "$id": "403", + "$id": "440", "name": "topAction", "resourceName": "SampleTypeSpec", "doc": "top level method", "accessibility": "public", "parameters": [ { - "$id": "404", + "$id": "441", "kind": "path", "name": "action", "serializedName": "action", "type": { - "$id": "405", + "$id": "442", "kind": "utcDateTime", "name": "utcDateTime", "encode": "rfc3339", "wireType": { - "$id": "406", + "$id": "443", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -4990,12 +5391,12 @@ "crossLanguageDefinitionId": "SampleTypeSpec.topAction.action" }, { - "$id": "407", + "$id": "444", "kind": "header", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "112" + "$ref": "116" }, "isApiVersion": false, "optional": false, @@ -5012,7 +5413,7 @@ 200 ], "bodyType": { - "$ref": "172" + "$ref": "196" }, "headers": [], "isErrorResponse": false, @@ -5032,17 +5433,17 @@ }, "parameters": [ { - "$id": "408", + "$id": "445", "kind": "method", "name": "action", "serializedName": "action", "type": { - "$id": "409", + "$id": "446", "kind": "utcDateTime", "name": "utcDateTime", "encode": "rfc3339", "wireType": { - "$id": "410", + "$id": "447", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -5061,12 +5462,12 @@ "decorators": [] }, { - "$id": "411", + "$id": "448", "kind": "method", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "112" + "$ref": "116" }, "location": "Header", "isApiVersion": false, @@ -5080,7 +5481,7 @@ ], "response": { "type": { - "$ref": "172" + "$ref": "196" } }, "isOverride": false, @@ -5089,7 +5490,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.topAction" }, { - "$id": "412", + "$id": "449", "kind": "basic", "name": "topAction2", "accessibility": "public", @@ -5099,19 +5500,19 @@ ], "doc": "top level method2", "operation": { - "$id": "413", + "$id": "450", "name": "topAction2", "resourceName": "SampleTypeSpec", "doc": "top level method2", "accessibility": "public", "parameters": [ { - "$id": "414", + "$id": "451", "kind": "header", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "114" + "$ref": "118" }, "isApiVersion": false, "optional": false, @@ -5128,7 +5529,7 @@ 200 ], "bodyType": { - "$ref": "172" + "$ref": "196" }, "headers": [], "isErrorResponse": false, @@ -5148,12 +5549,12 @@ }, "parameters": [ { - "$id": "415", + "$id": "452", "kind": "method", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "114" + "$ref": "118" }, "location": "Header", "isApiVersion": false, @@ -5167,7 +5568,7 @@ ], "response": { "type": { - "$ref": "172" + "$ref": "196" } }, "isOverride": false, @@ -5176,7 +5577,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.topAction2" }, { - "$id": "416", + "$id": "453", "kind": "basic", "name": "patchAction", "accessibility": "public", @@ -5186,20 +5587,20 @@ ], "doc": "top level patch", "operation": { - "$id": "417", + "$id": "454", "name": "patchAction", "resourceName": "SampleTypeSpec", "doc": "top level patch", "accessibility": "public", "parameters": [ { - "$id": "418", + "$id": "455", "kind": "header", "name": "contentType", "serializedName": "Content-Type", "doc": "Body parameter's content type. Known values are application/json", "type": { - "$ref": "116" + "$ref": "120" }, "isApiVersion": false, "optional": false, @@ -5210,12 +5611,12 @@ "crossLanguageDefinitionId": "SampleTypeSpec.patchAction.contentType" }, { - "$id": "419", + "$id": "456", "kind": "header", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "118" + "$ref": "122" }, "isApiVersion": false, "optional": false, @@ -5226,12 +5627,12 @@ "crossLanguageDefinitionId": "SampleTypeSpec.patchAction.accept" }, { - "$id": "420", + "$id": "457", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$ref": "172" + "$ref": "196" }, "isApiVersion": false, "contentTypes": [ @@ -5251,7 +5652,7 @@ 200 ], "bodyType": { - "$ref": "172" + "$ref": "196" }, "headers": [], "isErrorResponse": false, @@ -5274,12 +5675,12 @@ }, "parameters": [ { - "$id": "421", + "$id": "458", "kind": "method", "name": "body", "serializedName": "body", "type": { - "$ref": "172" + "$ref": "196" }, "location": "Body", "isApiVersion": false, @@ -5291,13 +5692,13 @@ "decorators": [] }, { - "$id": "422", + "$id": "459", "kind": "method", "name": "contentType", "serializedName": "Content-Type", "doc": "Body parameter's content type. Known values are application/json", "type": { - "$ref": "116" + "$ref": "120" }, "location": "Header", "isApiVersion": false, @@ -5309,12 +5710,12 @@ "decorators": [] }, { - "$id": "423", + "$id": "460", "kind": "method", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "118" + "$ref": "122" }, "location": "Header", "isApiVersion": false, @@ -5328,7 +5729,7 @@ ], "response": { "type": { - "$ref": "172" + "$ref": "196" } }, "isOverride": false, @@ -5337,7 +5738,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.patchAction" }, { - "$id": "424", + "$id": "461", "kind": "basic", "name": "anonymousBody", "accessibility": "public", @@ -5347,19 +5748,19 @@ ], "doc": "body parameter without body decorator", "operation": { - "$id": "425", + "$id": "462", "name": "anonymousBody", "resourceName": "SampleTypeSpec", "doc": "body parameter without body decorator", "accessibility": "public", "parameters": [ { - "$id": "426", + "$id": "463", "kind": "query", "name": "requiredQueryParam", "serializedName": "requiredQueryParam", "type": { - "$ref": "120" + "$ref": "124" }, "isApiVersion": false, "explode": false, @@ -5370,12 +5771,12 @@ "readOnly": false }, { - "$id": "427", + "$id": "464", "kind": "header", "name": "requiredHeader", "serializedName": "required-header", "type": { - "$ref": "122" + "$ref": "126" }, "isApiVersion": false, "optional": false, @@ -5386,13 +5787,13 @@ "crossLanguageDefinitionId": "SampleTypeSpec.anonymousBody.requiredHeader" }, { - "$id": "428", + "$id": "465", "kind": "header", "name": "contentType", "serializedName": "Content-Type", "doc": "Body parameter's content type. Known values are application/json", "type": { - "$ref": "124" + "$ref": "128" }, "isApiVersion": false, "optional": false, @@ -5403,12 +5804,12 @@ "crossLanguageDefinitionId": "SampleTypeSpec.anonymousBody.contentType" }, { - "$id": "429", + "$id": "466", "kind": "header", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "126" + "$ref": "130" }, "isApiVersion": false, "optional": false, @@ -5419,12 +5820,12 @@ "crossLanguageDefinitionId": "SampleTypeSpec.anonymousBody.accept" }, { - "$id": "430", + "$id": "467", "kind": "body", "name": "thing", "serializedName": "thing", "type": { - "$ref": "172" + "$ref": "196" }, "isApiVersion": false, "contentTypes": [ @@ -5444,7 +5845,7 @@ 200 ], "bodyType": { - "$ref": "172" + "$ref": "196" }, "headers": [], "isErrorResponse": false, @@ -5467,13 +5868,13 @@ }, "parameters": [ { - "$id": "431", + "$id": "468", "kind": "method", "name": "name", "serializedName": "name", "doc": "name of the Thing", "type": { - "$id": "432", + "$id": "469", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -5489,13 +5890,13 @@ "decorators": [] }, { - "$id": "433", + "$id": "470", "kind": "method", "name": "requiredUnion", "serializedName": "requiredUnion", "doc": "required Union", "type": { - "$ref": "176" + "$ref": "200" }, "location": "Body", "isApiVersion": false, @@ -5507,7 +5908,7 @@ "decorators": [] }, { - "$id": "434", + "$id": "471", "kind": "method", "name": "requiredLiteralString", "serializedName": "requiredLiteralString", @@ -5525,13 +5926,13 @@ "decorators": [] }, { - "$id": "435", + "$id": "472", "kind": "method", "name": "requiredNullableString", "serializedName": "requiredNullableString", "doc": "required nullable string", "type": { - "$ref": "183" + "$ref": "207" }, "location": "Body", "isApiVersion": false, @@ -5543,13 +5944,13 @@ "decorators": [] }, { - "$id": "436", + "$id": "473", "kind": "method", "name": "optionalNullableString", "serializedName": "optionalNullableString", "doc": "required optional string", "type": { - "$ref": "186" + "$ref": "210" }, "location": "Body", "isApiVersion": false, @@ -5561,7 +5962,7 @@ "decorators": [] }, { - "$id": "437", + "$id": "474", "kind": "method", "name": "requiredLiteralInt", "serializedName": "requiredLiteralInt", @@ -5579,7 +5980,7 @@ "decorators": [] }, { - "$id": "438", + "$id": "475", "kind": "method", "name": "requiredLiteralFloat", "serializedName": "requiredLiteralFloat", @@ -5597,7 +5998,7 @@ "decorators": [] }, { - "$id": "439", + "$id": "476", "kind": "method", "name": "requiredLiteralBool", "serializedName": "requiredLiteralBool", @@ -5615,18 +6016,18 @@ "decorators": [] }, { - "$id": "440", + "$id": "477", "kind": "method", "name": "optionalLiteralString", "serializedName": "optionalLiteralString", "doc": "optional literal string", "type": { - "$id": "441", + "$id": "478", "kind": "enum", "name": "ThingOptionalLiteralString", "crossLanguageDefinitionId": "", "valueType": { - "$id": "442", + "$id": "479", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -5634,12 +6035,12 @@ }, "values": [ { - "$id": "443", + "$id": "480", "kind": "enumvalue", "name": "reject", "value": "reject", "valueType": { - "$id": "444", + "$id": "481", "kind": "string", "decorators": [], "doc": "A sequence of textual characters.", @@ -5647,7 +6048,7 @@ "crossLanguageDefinitionId": "TypeSpec.string" }, "enumType": { - "$ref": "441" + "$ref": "478" }, "decorators": [] } @@ -5668,13 +6069,13 @@ "decorators": [] }, { - "$id": "445", + "$id": "482", "kind": "method", "name": "requiredNullableLiteralString", "serializedName": "requiredNullableLiteralString", "doc": "required nullable literal string", "type": { - "$ref": "193" + "$ref": "217" }, "location": "Body", "isApiVersion": false, @@ -5686,18 +6087,18 @@ "decorators": [] }, { - "$id": "446", + "$id": "483", "kind": "method", "name": "optionalLiteralInt", "serializedName": "optionalLiteralInt", "doc": "optional literal int", "type": { - "$id": "447", + "$id": "484", "kind": "enum", "name": "ThingOptionalLiteralInt", "crossLanguageDefinitionId": "", "valueType": { - "$id": "448", + "$id": "485", "kind": "int32", "name": "int32", "crossLanguageDefinitionId": "TypeSpec.int32", @@ -5705,12 +6106,12 @@ }, "values": [ { - "$id": "449", + "$id": "486", "kind": "enumvalue", "name": "456", "value": 456, "valueType": { - "$id": "450", + "$id": "487", "kind": "int32", "decorators": [], "doc": "A 32-bit integer. (`-2,147,483,648` to `2,147,483,647`)", @@ -5718,7 +6119,7 @@ "crossLanguageDefinitionId": "TypeSpec.int32" }, "enumType": { - "$ref": "447" + "$ref": "484" }, "decorators": [] } @@ -5739,18 +6140,18 @@ "decorators": [] }, { - "$id": "451", + "$id": "488", "kind": "method", "name": "optionalLiteralFloat", "serializedName": "optionalLiteralFloat", "doc": "optional literal float", "type": { - "$id": "452", + "$id": "489", "kind": "enum", "name": "ThingOptionalLiteralFloat", "crossLanguageDefinitionId": "", "valueType": { - "$id": "453", + "$id": "490", "kind": "float32", "name": "float32", "crossLanguageDefinitionId": "TypeSpec.float32", @@ -5758,12 +6159,12 @@ }, "values": [ { - "$id": "454", + "$id": "491", "kind": "enumvalue", "name": "4.56", "value": 4.56, "valueType": { - "$id": "455", + "$id": "492", "kind": "float32", "decorators": [], "doc": "A 32 bit floating point number. (`±1.5 x 10^−45` to `±3.4 x 10^38`)", @@ -5771,7 +6172,7 @@ "crossLanguageDefinitionId": "TypeSpec.float32" }, "enumType": { - "$ref": "452" + "$ref": "489" }, "decorators": [] } @@ -5792,7 +6193,7 @@ "decorators": [] }, { - "$id": "456", + "$id": "493", "kind": "method", "name": "optionalLiteralBool", "serializedName": "optionalLiteralBool", @@ -5810,13 +6211,13 @@ "decorators": [] }, { - "$id": "457", + "$id": "494", "kind": "method", "name": "requiredBadDescription", "serializedName": "requiredBadDescription", "doc": "description with xml <|endoftext|>", "type": { - "$id": "458", + "$id": "495", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -5832,13 +6233,13 @@ "decorators": [] }, { - "$id": "459", + "$id": "496", "kind": "method", "name": "optionalNullableList", "serializedName": "optionalNullableList", "doc": "optional nullable collection", "type": { - "$ref": "200" + "$ref": "224" }, "location": "Body", "isApiVersion": false, @@ -5850,13 +6251,13 @@ "decorators": [] }, { - "$id": "460", + "$id": "497", "kind": "method", "name": "requiredNullableList", "serializedName": "requiredNullableList", "doc": "required nullable collection", "type": { - "$ref": "204" + "$ref": "228" }, "location": "Body", "isApiVersion": false, @@ -5868,12 +6269,12 @@ "decorators": [] }, { - "$id": "461", + "$id": "498", "kind": "method", "name": "requiredQueryParam", "serializedName": "requiredQueryParam", "type": { - "$ref": "138" + "$ref": "142" }, "location": "Query", "isApiVersion": false, @@ -5885,12 +6286,12 @@ "decorators": [] }, { - "$id": "462", + "$id": "499", "kind": "method", "name": "requiredHeader", "serializedName": "required-header", "type": { - "$ref": "140" + "$ref": "144" }, "location": "Header", "isApiVersion": false, @@ -5902,13 +6303,13 @@ "decorators": [] }, { - "$id": "463", + "$id": "500", "kind": "method", "name": "contentType", "serializedName": "Content-Type", "doc": "Body parameter's content type. Known values are application/json", "type": { - "$ref": "124" + "$ref": "128" }, "location": "Header", "isApiVersion": false, @@ -5920,12 +6321,12 @@ "decorators": [] }, { - "$id": "464", + "$id": "501", "kind": "method", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "126" + "$ref": "130" }, "location": "Header", "isApiVersion": false, @@ -5939,7 +6340,7 @@ ], "response": { "type": { - "$ref": "172" + "$ref": "196" } }, "isOverride": false, @@ -5948,7 +6349,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.anonymousBody" }, { - "$id": "465", + "$id": "502", "kind": "basic", "name": "friendlyModel", "accessibility": "public", @@ -5958,20 +6359,20 @@ ], "doc": "Model can have its friendly name", "operation": { - "$id": "466", + "$id": "503", "name": "friendlyModel", "resourceName": "SampleTypeSpec", "doc": "Model can have its friendly name", "accessibility": "public", "parameters": [ { - "$id": "467", + "$id": "504", "kind": "header", "name": "contentType", "serializedName": "Content-Type", "doc": "Body parameter's content type. Known values are application/json", "type": { - "$ref": "142" + "$ref": "146" }, "isApiVersion": false, "optional": false, @@ -5982,12 +6383,12 @@ "crossLanguageDefinitionId": "SampleTypeSpec.friendlyModel.contentType" }, { - "$id": "468", + "$id": "505", "kind": "header", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "144" + "$ref": "148" }, "isApiVersion": false, "optional": false, @@ -5998,12 +6399,12 @@ "crossLanguageDefinitionId": "SampleTypeSpec.friendlyModel.accept" }, { - "$id": "469", + "$id": "506", "kind": "body", "name": "friend", "serializedName": "friend", "type": { - "$ref": "253" + "$ref": "277" }, "isApiVersion": false, "contentTypes": [ @@ -6023,7 +6424,7 @@ 200 ], "bodyType": { - "$ref": "253" + "$ref": "277" }, "headers": [], "isErrorResponse": false, @@ -6046,13 +6447,13 @@ }, "parameters": [ { - "$id": "470", + "$id": "507", "kind": "method", "name": "name", "serializedName": "name", "doc": "name of the NotFriend", "type": { - "$id": "471", + "$id": "508", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -6068,13 +6469,13 @@ "decorators": [] }, { - "$id": "472", + "$id": "509", "kind": "method", "name": "contentType", "serializedName": "Content-Type", "doc": "Body parameter's content type. Known values are application/json", "type": { - "$ref": "142" + "$ref": "146" }, "location": "Header", "isApiVersion": false, @@ -6086,12 +6487,12 @@ "decorators": [] }, { - "$id": "473", + "$id": "510", "kind": "method", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "144" + "$ref": "148" }, "location": "Header", "isApiVersion": false, @@ -6105,7 +6506,7 @@ ], "response": { "type": { - "$ref": "253" + "$ref": "277" } }, "isOverride": false, @@ -6114,7 +6515,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.friendlyModel" }, { - "$id": "474", + "$id": "511", "kind": "basic", "name": "addTimeHeader", "accessibility": "public", @@ -6123,23 +6524,23 @@ "2024-08-16-preview" ], "operation": { - "$id": "475", + "$id": "512", "name": "addTimeHeader", "resourceName": "SampleTypeSpec", "accessibility": "public", "parameters": [ { - "$id": "476", + "$id": "513", "kind": "header", "name": "repeatabilityFirstSent", "serializedName": "Repeatability-First-Sent", "type": { - "$id": "477", + "$id": "514", "kind": "utcDateTime", "name": "utcDateTime", "encode": "rfc7231", "wireType": { - "$id": "478", + "$id": "515", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -6177,17 +6578,17 @@ }, "parameters": [ { - "$id": "479", + "$id": "516", "kind": "method", "name": "repeatabilityFirstSent", "serializedName": "Repeatability-First-Sent", "type": { - "$id": "480", + "$id": "517", "kind": "utcDateTime", "name": "utcDateTime", "encode": "rfc7231", "wireType": { - "$id": "481", + "$id": "518", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -6213,7 +6614,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.addTimeHeader" }, { - "$id": "482", + "$id": "519", "kind": "basic", "name": "projectedNameModel", "accessibility": "public", @@ -6223,20 +6624,20 @@ ], "doc": "Model can have its projected name", "operation": { - "$id": "483", + "$id": "520", "name": "projectedNameModel", "resourceName": "SampleTypeSpec", "doc": "Model can have its projected name", "accessibility": "public", "parameters": [ { - "$id": "484", + "$id": "521", "kind": "header", "name": "contentType", "serializedName": "Content-Type", "doc": "Body parameter's content type. Known values are application/json", "type": { - "$ref": "146" + "$ref": "150" }, "isApiVersion": false, "optional": false, @@ -6247,12 +6648,12 @@ "crossLanguageDefinitionId": "SampleTypeSpec.projectedNameModel.contentType" }, { - "$id": "485", + "$id": "522", "kind": "header", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "148" + "$ref": "152" }, "isApiVersion": false, "optional": false, @@ -6263,12 +6664,12 @@ "crossLanguageDefinitionId": "SampleTypeSpec.projectedNameModel.accept" }, { - "$id": "486", + "$id": "523", "kind": "body", "name": "renamedModel", "serializedName": "renamedModel", "type": { - "$ref": "256" + "$ref": "280" }, "isApiVersion": false, "contentTypes": [ @@ -6288,7 +6689,7 @@ 200 ], "bodyType": { - "$ref": "256" + "$ref": "280" }, "headers": [], "isErrorResponse": false, @@ -6311,13 +6712,13 @@ }, "parameters": [ { - "$id": "487", + "$id": "524", "kind": "method", "name": "otherName", "serializedName": "otherName", "doc": "name of the ModelWithClientName", "type": { - "$id": "488", + "$id": "525", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -6333,13 +6734,13 @@ "decorators": [] }, { - "$id": "489", + "$id": "526", "kind": "method", "name": "contentType", "serializedName": "Content-Type", "doc": "Body parameter's content type. Known values are application/json", "type": { - "$ref": "146" + "$ref": "150" }, "location": "Header", "isApiVersion": false, @@ -6351,12 +6752,12 @@ "decorators": [] }, { - "$id": "490", + "$id": "527", "kind": "method", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "148" + "$ref": "152" }, "location": "Header", "isApiVersion": false, @@ -6370,7 +6771,7 @@ ], "response": { "type": { - "$ref": "256" + "$ref": "280" } }, "isOverride": false, @@ -6379,7 +6780,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.projectedNameModel" }, { - "$id": "491", + "$id": "528", "kind": "basic", "name": "returnsAnonymousModel", "accessibility": "public", @@ -6389,19 +6790,19 @@ ], "doc": "return anonymous model", "operation": { - "$id": "492", + "$id": "529", "name": "returnsAnonymousModel", "resourceName": "SampleTypeSpec", "doc": "return anonymous model", "accessibility": "public", "parameters": [ { - "$id": "493", + "$id": "530", "kind": "header", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "150" + "$ref": "154" }, "isApiVersion": false, "optional": false, @@ -6418,7 +6819,7 @@ 200 ], "bodyType": { - "$ref": "259" + "$ref": "283" }, "headers": [], "isErrorResponse": false, @@ -6438,12 +6839,12 @@ }, "parameters": [ { - "$id": "494", + "$id": "531", "kind": "method", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "150" + "$ref": "154" }, "location": "Header", "isApiVersion": false, @@ -6457,7 +6858,7 @@ ], "response": { "type": { - "$ref": "259" + "$ref": "283" } }, "isOverride": false, @@ -6466,7 +6867,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.returnsAnonymousModel" }, { - "$id": "495", + "$id": "532", "kind": "basic", "name": "getUnknownValue", "accessibility": "public", @@ -6476,19 +6877,19 @@ ], "doc": "get extensible enum", "operation": { - "$id": "496", + "$id": "533", "name": "getUnknownValue", "resourceName": "SampleTypeSpec", "doc": "get extensible enum", "accessibility": "public", "parameters": [ { - "$id": "497", + "$id": "534", "kind": "header", "name": "accept", "serializedName": "Accept", "type": { - "$id": "498", + "$id": "535", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -6509,7 +6910,7 @@ 200 ], "bodyType": { - "$id": "499", + "$id": "536", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -6540,12 +6941,12 @@ }, "parameters": [ { - "$id": "500", + "$id": "537", "kind": "method", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "498" + "$ref": "535" }, "location": "Header", "isApiVersion": false, @@ -6559,7 +6960,7 @@ ], "response": { "type": { - "$ref": "499" + "$ref": "536" } }, "isOverride": false, @@ -6568,7 +6969,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.getUnknownValue" }, { - "$id": "501", + "$id": "538", "kind": "basic", "name": "internalProtocol", "accessibility": "public", @@ -6578,20 +6979,20 @@ ], "doc": "When set protocol false and convenient true, then the protocol method should be internal", "operation": { - "$id": "502", + "$id": "539", "name": "internalProtocol", "resourceName": "SampleTypeSpec", "doc": "When set protocol false and convenient true, then the protocol method should be internal", "accessibility": "public", "parameters": [ { - "$id": "503", + "$id": "540", "kind": "header", "name": "contentType", "serializedName": "Content-Type", "doc": "Body parameter's content type. Known values are application/json", "type": { - "$ref": "152" + "$ref": "156" }, "isApiVersion": false, "optional": false, @@ -6602,12 +7003,12 @@ "crossLanguageDefinitionId": "SampleTypeSpec.internalProtocol.contentType" }, { - "$id": "504", + "$id": "541", "kind": "header", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "154" + "$ref": "158" }, "isApiVersion": false, "optional": false, @@ -6618,12 +7019,12 @@ "crossLanguageDefinitionId": "SampleTypeSpec.internalProtocol.accept" }, { - "$id": "505", + "$id": "542", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$ref": "172" + "$ref": "196" }, "isApiVersion": false, "contentTypes": [ @@ -6643,7 +7044,7 @@ 200 ], "bodyType": { - "$ref": "172" + "$ref": "196" }, "headers": [], "isErrorResponse": false, @@ -6666,12 +7067,12 @@ }, "parameters": [ { - "$id": "506", + "$id": "543", "kind": "method", "name": "body", "serializedName": "body", "type": { - "$ref": "172" + "$ref": "196" }, "location": "Body", "isApiVersion": false, @@ -6683,13 +7084,13 @@ "decorators": [] }, { - "$id": "507", + "$id": "544", "kind": "method", "name": "contentType", "serializedName": "Content-Type", "doc": "Body parameter's content type. Known values are application/json", "type": { - "$ref": "152" + "$ref": "156" }, "location": "Header", "isApiVersion": false, @@ -6701,12 +7102,12 @@ "decorators": [] }, { - "$id": "508", + "$id": "545", "kind": "method", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "154" + "$ref": "158" }, "location": "Header", "isApiVersion": false, @@ -6720,7 +7121,7 @@ ], "response": { "type": { - "$ref": "172" + "$ref": "196" } }, "isOverride": false, @@ -6729,7 +7130,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.internalProtocol" }, { - "$id": "509", + "$id": "546", "kind": "basic", "name": "stillConvenient", "accessibility": "public", @@ -6739,7 +7140,7 @@ ], "doc": "When set protocol false and convenient true, the convenient method should be generated even it has the same signature as protocol one", "operation": { - "$id": "510", + "$id": "547", "name": "stillConvenient", "resourceName": "SampleTypeSpec", "doc": "When set protocol false and convenient true, the convenient method should be generated even it has the same signature as protocol one", @@ -6771,7 +7172,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.stillConvenient" }, { - "$id": "511", + "$id": "548", "kind": "basic", "name": "headAsBoolean", "accessibility": "public", @@ -6781,19 +7182,19 @@ ], "doc": "head as boolean.", "operation": { - "$id": "512", + "$id": "549", "name": "headAsBoolean", "resourceName": "SampleTypeSpec", "doc": "head as boolean.", "accessibility": "public", "parameters": [ { - "$id": "513", + "$id": "550", "kind": "path", "name": "id", "serializedName": "id", "type": { - "$id": "514", + "$id": "551", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -6831,12 +7232,12 @@ }, "parameters": [ { - "$id": "515", + "$id": "552", "kind": "method", "name": "id", "serializedName": "id", "type": { - "$id": "516", + "$id": "553", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -6859,7 +7260,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.headAsBoolean" }, { - "$id": "517", + "$id": "554", "kind": "basic", "name": "WithApiVersion", "accessibility": "public", @@ -6869,19 +7270,19 @@ ], "doc": "Return hi again", "operation": { - "$id": "518", + "$id": "555", "name": "WithApiVersion", "resourceName": "SampleTypeSpec", "doc": "Return hi again", "accessibility": "public", "parameters": [ { - "$id": "519", + "$id": "556", "kind": "header", "name": "p1", "serializedName": "p1", "type": { - "$id": "520", + "$id": "557", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -6896,12 +7297,12 @@ "crossLanguageDefinitionId": "SampleTypeSpec.WithApiVersion.p1" }, { - "$id": "521", + "$id": "558", "kind": "query", "name": "apiVersion", "serializedName": "apiVersion", "type": { - "$id": "522", + "$id": "559", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -6911,7 +7312,7 @@ "explode": false, "defaultValue": { "type": { - "$id": "523", + "$id": "560", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string" @@ -6945,12 +7346,12 @@ }, "parameters": [ { - "$id": "524", + "$id": "561", "kind": "method", "name": "p1", "serializedName": "p1", "type": { - "$id": "525", + "$id": "562", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -6973,7 +7374,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.WithApiVersion" }, { - "$id": "526", + "$id": "563", "kind": "paging", "name": "ListWithNextLink", "accessibility": "public", @@ -6983,19 +7384,19 @@ ], "doc": "List things with nextlink", "operation": { - "$id": "527", + "$id": "564", "name": "ListWithNextLink", "resourceName": "SampleTypeSpec", "doc": "List things with nextlink", "accessibility": "public", "parameters": [ { - "$id": "528", + "$id": "565", "kind": "header", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "156" + "$ref": "160" }, "isApiVersion": false, "optional": false, @@ -7012,7 +7413,7 @@ 200 ], "bodyType": { - "$ref": "260" + "$ref": "284" }, "headers": [], "isErrorResponse": false, @@ -7032,12 +7433,12 @@ }, "parameters": [ { - "$id": "529", + "$id": "566", "kind": "method", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "156" + "$ref": "160" }, "location": "Header", "isApiVersion": false, @@ -7051,7 +7452,7 @@ ], "response": { "type": { - "$ref": "262" + "$ref": "286" }, "resultSegments": [ "things" @@ -7075,7 +7476,7 @@ } }, { - "$id": "530", + "$id": "567", "kind": "paging", "name": "ListWithStringNextLink", "accessibility": "public", @@ -7085,19 +7486,19 @@ ], "doc": "List things with nextlink", "operation": { - "$id": "531", + "$id": "568", "name": "ListWithStringNextLink", "resourceName": "SampleTypeSpec", "doc": "List things with nextlink", "accessibility": "public", "parameters": [ { - "$id": "532", + "$id": "569", "kind": "header", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "158" + "$ref": "162" }, "isApiVersion": false, "optional": false, @@ -7114,7 +7515,7 @@ 200 ], "bodyType": { - "$ref": "265" + "$ref": "289" }, "headers": [], "isErrorResponse": false, @@ -7134,12 +7535,12 @@ }, "parameters": [ { - "$id": "533", + "$id": "570", "kind": "method", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "158" + "$ref": "162" }, "location": "Header", "isApiVersion": false, @@ -7153,7 +7554,7 @@ ], "response": { "type": { - "$ref": "262" + "$ref": "286" }, "resultSegments": [ "things" @@ -7177,7 +7578,7 @@ } }, { - "$id": "534", + "$id": "571", "kind": "paging", "name": "ListWithContinuationToken", "accessibility": "public", @@ -7187,19 +7588,19 @@ ], "doc": "List things with continuation token", "operation": { - "$id": "535", + "$id": "572", "name": "ListWithContinuationToken", "resourceName": "SampleTypeSpec", "doc": "List things with continuation token", "accessibility": "public", "parameters": [ { - "$id": "536", + "$id": "573", "kind": "query", "name": "token", "serializedName": "token", "type": { - "$id": "537", + "$id": "574", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -7214,12 +7615,12 @@ "readOnly": false }, { - "$id": "538", + "$id": "575", "kind": "header", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "160" + "$ref": "164" }, "isApiVersion": false, "optional": false, @@ -7236,7 +7637,7 @@ 200 ], "bodyType": { - "$ref": "269" + "$ref": "293" }, "headers": [], "isErrorResponse": false, @@ -7256,12 +7657,12 @@ }, "parameters": [ { - "$id": "539", + "$id": "576", "kind": "method", "name": "token", "serializedName": "token", "type": { - "$id": "540", + "$id": "577", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -7277,12 +7678,12 @@ "decorators": [] }, { - "$id": "541", + "$id": "578", "kind": "method", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "160" + "$ref": "164" }, "location": "Header", "isApiVersion": false, @@ -7296,7 +7697,7 @@ ], "response": { "type": { - "$ref": "262" + "$ref": "286" }, "resultSegments": [ "things" @@ -7312,7 +7713,7 @@ ], "continuationToken": { "parameter": { - "$ref": "536" + "$ref": "573" }, "responseSegments": [ "nextToken" @@ -7323,7 +7724,7 @@ } }, { - "$id": "542", + "$id": "579", "kind": "paging", "name": "ListWithContinuationTokenHeaderResponse", "accessibility": "public", @@ -7333,19 +7734,19 @@ ], "doc": "List things with continuation token header response", "operation": { - "$id": "543", + "$id": "580", "name": "ListWithContinuationTokenHeaderResponse", "resourceName": "SampleTypeSpec", "doc": "List things with continuation token header response", "accessibility": "public", "parameters": [ { - "$id": "544", + "$id": "581", "kind": "query", "name": "token", "serializedName": "token", "type": { - "$id": "545", + "$id": "582", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -7360,12 +7761,12 @@ "readOnly": false }, { - "$id": "546", + "$id": "583", "kind": "header", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "162" + "$ref": "166" }, "isApiVersion": false, "optional": false, @@ -7382,14 +7783,14 @@ 200 ], "bodyType": { - "$ref": "273" + "$ref": "297" }, "headers": [ { "name": "nextToken", "nameInResponse": "next-token", "type": { - "$id": "547", + "$id": "584", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -7414,12 +7815,12 @@ }, "parameters": [ { - "$id": "548", + "$id": "585", "kind": "method", "name": "token", "serializedName": "token", "type": { - "$id": "549", + "$id": "586", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -7435,12 +7836,12 @@ "decorators": [] }, { - "$id": "550", + "$id": "587", "kind": "method", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "162" + "$ref": "166" }, "location": "Header", "isApiVersion": false, @@ -7454,7 +7855,7 @@ ], "response": { "type": { - "$ref": "262" + "$ref": "286" }, "resultSegments": [ "things" @@ -7470,7 +7871,7 @@ ], "continuationToken": { "parameter": { - "$ref": "544" + "$ref": "581" }, "responseSegments": [ "next-token" @@ -7481,7 +7882,7 @@ } }, { - "$id": "551", + "$id": "588", "kind": "paging", "name": "ListWithPaging", "accessibility": "public", @@ -7491,19 +7892,19 @@ ], "doc": "List things with paging", "operation": { - "$id": "552", + "$id": "589", "name": "ListWithPaging", "resourceName": "SampleTypeSpec", "doc": "List things with paging", "accessibility": "public", "parameters": [ { - "$id": "553", + "$id": "590", "kind": "header", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "164" + "$ref": "168" }, "isApiVersion": false, "optional": false, @@ -7520,7 +7921,7 @@ 200 ], "bodyType": { - "$ref": "275" + "$ref": "299" }, "headers": [], "isErrorResponse": false, @@ -7540,12 +7941,12 @@ }, "parameters": [ { - "$id": "554", + "$id": "591", "kind": "method", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "164" + "$ref": "168" }, "location": "Header", "isApiVersion": false, @@ -7559,7 +7960,7 @@ ], "response": { "type": { - "$ref": "262" + "$ref": "286" }, "resultSegments": [ "items" @@ -7577,7 +7978,7 @@ } }, { - "$id": "555", + "$id": "592", "kind": "basic", "name": "EmbeddedParameters", "accessibility": "public", @@ -7587,20 +7988,20 @@ ], "doc": "An operation with embedded parameters within the body", "operation": { - "$id": "556", + "$id": "593", "name": "EmbeddedParameters", "resourceName": "SampleTypeSpec", "doc": "An operation with embedded parameters within the body", "accessibility": "public", "parameters": [ { - "$id": "557", + "$id": "594", "kind": "header", "name": "requiredHeader", "serializedName": "required-header", "doc": "required header parameter", "type": { - "$id": "558", + "$id": "595", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -7615,13 +8016,13 @@ "crossLanguageDefinitionId": "SampleTypeSpec.ModelWithEmbeddedNonBodyParameters.requiredHeader" }, { - "$id": "559", + "$id": "596", "kind": "header", "name": "optionalHeader", "serializedName": "optional-header", "doc": "optional header parameter", "type": { - "$id": "560", + "$id": "597", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -7636,13 +8037,13 @@ "crossLanguageDefinitionId": "SampleTypeSpec.ModelWithEmbeddedNonBodyParameters.optionalHeader" }, { - "$id": "561", + "$id": "598", "kind": "query", "name": "requiredQuery", "serializedName": "requiredQuery", "doc": "required query parameter", "type": { - "$id": "562", + "$id": "599", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -7657,13 +8058,13 @@ "readOnly": false }, { - "$id": "563", + "$id": "600", "kind": "query", "name": "optionalQuery", "serializedName": "optionalQuery", "doc": "optional query parameter", "type": { - "$id": "564", + "$id": "601", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -7678,13 +8079,13 @@ "readOnly": false }, { - "$id": "565", + "$id": "602", "kind": "header", "name": "contentType", "serializedName": "Content-Type", "doc": "Body parameter's content type. Known values are application/json", "type": { - "$ref": "166" + "$ref": "170" }, "isApiVersion": false, "optional": false, @@ -7695,12 +8096,12 @@ "crossLanguageDefinitionId": "SampleTypeSpec.EmbeddedParameters.contentType" }, { - "$id": "566", + "$id": "603", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$ref": "277" + "$ref": "301" }, "isApiVersion": false, "contentTypes": [ @@ -7737,12 +8138,12 @@ }, "parameters": [ { - "$id": "567", + "$id": "604", "kind": "method", "name": "body", "serializedName": "body", "type": { - "$ref": "277" + "$ref": "301" }, "location": "Body", "isApiVersion": false, @@ -7754,13 +8155,13 @@ "decorators": [] }, { - "$id": "568", + "$id": "605", "kind": "method", "name": "contentType", "serializedName": "Content-Type", "doc": "Body parameter's content type. Known values are application/json", "type": { - "$ref": "166" + "$ref": "170" }, "location": "Header", "isApiVersion": false, @@ -7779,7 +8180,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.EmbeddedParameters" }, { - "$id": "569", + "$id": "606", "kind": "basic", "name": "DynamicModelOperation", "accessibility": "public", @@ -7789,20 +8190,20 @@ ], "doc": "An operation with a dynamic model", "operation": { - "$id": "570", + "$id": "607", "name": "DynamicModelOperation", "resourceName": "SampleTypeSpec", "doc": "An operation with a dynamic model", "accessibility": "public", "parameters": [ { - "$id": "571", + "$id": "608", "kind": "header", "name": "contentType", "serializedName": "Content-Type", "doc": "Body parameter's content type. Known values are application/json", "type": { - "$ref": "168" + "$ref": "172" }, "isApiVersion": false, "optional": false, @@ -7813,12 +8214,12 @@ "crossLanguageDefinitionId": "SampleTypeSpec.DynamicModelOperation.contentType" }, { - "$id": "572", + "$id": "609", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$ref": "288" + "$ref": "312" }, "isApiVersion": false, "contentTypes": [ @@ -7855,12 +8256,12 @@ }, "parameters": [ { - "$id": "573", + "$id": "610", "kind": "method", "name": "body", "serializedName": "body", "type": { - "$ref": "288" + "$ref": "312" }, "location": "Body", "isApiVersion": false, @@ -7872,13 +8273,13 @@ "decorators": [] }, { - "$id": "574", + "$id": "611", "kind": "method", "name": "contentType", "serializedName": "Content-Type", "doc": "Body parameter's content type. Known values are application/json", "type": { - "$ref": "168" + "$ref": "172" }, "location": "Header", "isApiVersion": false, @@ -7899,12 +8300,12 @@ ], "parameters": [ { - "$id": "575", + "$id": "612", "kind": "endpoint", "name": "sampleTypeSpecUrl", "serializedName": "sampleTypeSpecUrl", "type": { - "$id": "576", + "$id": "613", "kind": "url", "name": "endpoint", "crossLanguageDefinitionId": "TypeSpec.url" @@ -7919,12 +8320,12 @@ "crossLanguageDefinitionId": "SampleTypeSpec.sampleTypeSpecUrl" }, { - "$id": "577", + "$id": "614", "kind": "method", "name": "apiVersion", "serializedName": "apiVersion", "type": { - "$id": "578", + "$id": "615", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -7934,7 +8335,7 @@ "isApiVersion": true, "defaultValue": { "type": { - "$id": "579", + "$id": "616", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string" @@ -7958,54 +8359,213 @@ ], "children": [ { - "$id": "580", + "$id": "617", "kind": "client", - "name": "Metrics", + "name": "AnimalOperations", "namespace": "SampleTypeSpec", "methods": [ { - "$id": "581", + "$id": "618", "kind": "basic", - "name": "getWidgetMetrics", + "name": "updatePetAsAnimal", "accessibility": "public", "apiVersions": [ "2024-07-16-preview", "2024-08-16-preview" ], - "doc": "Get Widget metrics for given day of week", + "doc": "Update a pet as an animal", "operation": { - "$id": "582", - "name": "getWidgetMetrics", - "resourceName": "Metrics", - "doc": "Get Widget metrics for given day of week", + "$id": "619", + "name": "updatePetAsAnimal", + "resourceName": "AnimalOperations", + "doc": "Update a pet as an animal", "accessibility": "public", "parameters": [ { - "$id": "583", - "kind": "path", - "name": "day", - "serializedName": "day", + "$id": "620", + "kind": "header", + "name": "contentType", + "serializedName": "Content-Type", + "doc": "Body parameter's content type. Known values are application/json", "type": { - "$ref": "57" + "$ref": "174" }, "isApiVersion": false, - "explode": false, - "style": "simple", - "allowReserved": false, - "skipUrlEncoding": false, + "optional": false, + "isContentType": true, + "scope": "Constant", + "readOnly": false, + "decorators": [], + "crossLanguageDefinitionId": "SampleTypeSpec.AnimalOperations.updatePetAsAnimal.contentType" + }, + { + "$id": "621", + "kind": "header", + "name": "accept", + "serializedName": "Accept", + "type": { + "$ref": "176" + }, + "isApiVersion": false, + "optional": false, + "isContentType": false, + "scope": "Constant", + "readOnly": false, + "decorators": [], + "crossLanguageDefinitionId": "SampleTypeSpec.AnimalOperations.updatePetAsAnimal.accept" + }, + { + "$id": "622", + "kind": "body", + "name": "animal", + "serializedName": "animal", + "type": { + "$ref": "350" + }, + "isApiVersion": false, + "contentTypes": [ + "application/json" + ], + "defaultContentType": "application/json", "optional": false, "scope": "Method", "decorators": [], "readOnly": false, - "crossLanguageDefinitionId": "SampleTypeSpec.Metrics.getWidgetMetrics.day" + "crossLanguageDefinitionId": "SampleTypeSpec.AnimalOperations.updatePetAsAnimal.animal" + } + ], + "responses": [ + { + "statusCodes": [ + 200 + ], + "bodyType": { + "$ref": "350" + }, + "headers": [], + "isErrorResponse": false, + "contentTypes": [ + "application/json" + ] + } + ], + "httpMethod": "PUT", + "uri": "{sampleTypeSpecUrl}", + "path": "/animals/pet/as-animal", + "requestMediaTypes": [ + "application/json" + ], + "bufferResponse": true, + "generateProtocolMethod": true, + "generateConvenienceMethod": true, + "crossLanguageDefinitionId": "SampleTypeSpec.AnimalOperations.updatePetAsAnimal", + "decorators": [] + }, + "parameters": [ + { + "$id": "623", + "kind": "method", + "name": "animal", + "serializedName": "animal", + "type": { + "$ref": "350" + }, + "location": "Body", + "isApiVersion": false, + "optional": false, + "scope": "Method", + "crossLanguageDefinitionId": "SampleTypeSpec.AnimalOperations.updatePetAsAnimal.animal", + "readOnly": false, + "access": "public", + "decorators": [] + }, + { + "$id": "624", + "kind": "method", + "name": "contentType", + "serializedName": "Content-Type", + "doc": "Body parameter's content type. Known values are application/json", + "type": { + "$ref": "174" + }, + "location": "Header", + "isApiVersion": false, + "optional": false, + "scope": "Constant", + "crossLanguageDefinitionId": "SampleTypeSpec.AnimalOperations.updatePetAsAnimal.contentType", + "readOnly": false, + "access": "public", + "decorators": [] + }, + { + "$id": "625", + "kind": "method", + "name": "accept", + "serializedName": "Accept", + "type": { + "$ref": "176" + }, + "location": "Header", + "isApiVersion": false, + "optional": false, + "scope": "Constant", + "crossLanguageDefinitionId": "SampleTypeSpec.AnimalOperations.updatePetAsAnimal.accept", + "readOnly": false, + "access": "public", + "decorators": [] + } + ], + "response": { + "type": { + "$ref": "350" + } + }, + "isOverride": false, + "generateConvenient": true, + "generateProtocol": true, + "crossLanguageDefinitionId": "SampleTypeSpec.AnimalOperations.updatePetAsAnimal" + }, + { + "$id": "626", + "kind": "basic", + "name": "updateDogAsAnimal", + "accessibility": "public", + "apiVersions": [ + "2024-07-16-preview", + "2024-08-16-preview" + ], + "doc": "Update a dog as an animal", + "operation": { + "$id": "627", + "name": "updateDogAsAnimal", + "resourceName": "AnimalOperations", + "doc": "Update a dog as an animal", + "accessibility": "public", + "parameters": [ + { + "$id": "628", + "kind": "header", + "name": "contentType", + "serializedName": "Content-Type", + "doc": "Body parameter's content type. Known values are application/json", + "type": { + "$ref": "178" + }, + "isApiVersion": false, + "optional": false, + "isContentType": true, + "scope": "Constant", + "readOnly": false, + "decorators": [], + "crossLanguageDefinitionId": "SampleTypeSpec.AnimalOperations.updateDogAsAnimal.contentType" }, { - "$id": "584", + "$id": "629", "kind": "header", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "170" + "$ref": "180" }, "isApiVersion": false, "optional": false, @@ -8013,7 +8573,26 @@ "scope": "Constant", "readOnly": false, "decorators": [], - "crossLanguageDefinitionId": "SampleTypeSpec.Metrics.getWidgetMetrics.accept" + "crossLanguageDefinitionId": "SampleTypeSpec.AnimalOperations.updateDogAsAnimal.accept" + }, + { + "$id": "630", + "kind": "body", + "name": "animal", + "serializedName": "animal", + "type": { + "$ref": "350" + }, + "isApiVersion": false, + "contentTypes": [ + "application/json" + ], + "defaultContentType": "application/json", + "optional": false, + "scope": "Method", + "decorators": [], + "readOnly": false, + "crossLanguageDefinitionId": "SampleTypeSpec.AnimalOperations.updateDogAsAnimal.animal" } ], "responses": [ @@ -8022,7 +8601,7 @@ 200 ], "bodyType": { - "$ref": "326" + "$ref": "350" }, "headers": [], "isErrorResponse": false, @@ -8031,46 +8610,67 @@ ] } ], - "httpMethod": "GET", + "httpMethod": "PUT", "uri": "{sampleTypeSpecUrl}", - "path": "/metrics/widgets/daysOfWeek/{day}", + "path": "/animals/dog/as-animal", + "requestMediaTypes": [ + "application/json" + ], "bufferResponse": true, "generateProtocolMethod": true, "generateConvenienceMethod": true, - "crossLanguageDefinitionId": "SampleTypeSpec.Metrics.getWidgetMetrics", + "crossLanguageDefinitionId": "SampleTypeSpec.AnimalOperations.updateDogAsAnimal", "decorators": [] }, "parameters": [ { - "$id": "585", + "$id": "631", "kind": "method", - "name": "day", - "serializedName": "day", + "name": "animal", + "serializedName": "animal", "type": { - "$ref": "57" + "$ref": "350" }, - "location": "Path", + "location": "Body", "isApiVersion": false, "optional": false, "scope": "Method", - "crossLanguageDefinitionId": "SampleTypeSpec.Metrics.getWidgetMetrics.day", + "crossLanguageDefinitionId": "SampleTypeSpec.AnimalOperations.updateDogAsAnimal.animal", + "readOnly": false, + "access": "public", + "decorators": [] + }, + { + "$id": "632", + "kind": "method", + "name": "contentType", + "serializedName": "Content-Type", + "doc": "Body parameter's content type. Known values are application/json", + "type": { + "$ref": "178" + }, + "location": "Header", + "isApiVersion": false, + "optional": false, + "scope": "Constant", + "crossLanguageDefinitionId": "SampleTypeSpec.AnimalOperations.updateDogAsAnimal.contentType", "readOnly": false, "access": "public", "decorators": [] }, { - "$id": "586", + "$id": "633", "kind": "method", "name": "accept", "serializedName": "Accept", "type": { - "$ref": "170" + "$ref": "180" }, "location": "Header", "isApiVersion": false, "optional": false, "scope": "Constant", - "crossLanguageDefinitionId": "SampleTypeSpec.Metrics.getWidgetMetrics.accept", + "crossLanguageDefinitionId": "SampleTypeSpec.AnimalOperations.updateDogAsAnimal.accept", "readOnly": false, "access": "public", "decorators": [] @@ -8078,23 +8678,749 @@ ], "response": { "type": { - "$ref": "326" + "$ref": "350" } }, "isOverride": false, "generateConvenient": true, "generateProtocol": true, - "crossLanguageDefinitionId": "SampleTypeSpec.Metrics.getWidgetMetrics" + "crossLanguageDefinitionId": "SampleTypeSpec.AnimalOperations.updateDogAsAnimal" } ], "parameters": [ { - "$id": "587", + "$id": "634", + "kind": "endpoint", + "name": "sampleTypeSpecUrl", + "serializedName": "sampleTypeSpecUrl", + "type": { + "$id": "635", + "kind": "url", + "name": "endpoint", + "crossLanguageDefinitionId": "TypeSpec.url" + }, + "isApiVersion": false, + "optional": false, + "scope": "Client", + "isEndpoint": true, + "serverUrlTemplate": "{sampleTypeSpecUrl}", + "skipUrlEncoding": false, + "readOnly": false, + "crossLanguageDefinitionId": "SampleTypeSpec.sampleTypeSpecUrl" + } + ], + "initializedBy": 0, + "decorators": [], + "crossLanguageDefinitionId": "SampleTypeSpec.AnimalOperations", + "apiVersions": [ + "2024-07-16-preview", + "2024-08-16-preview" + ], + "parent": { + "$ref": "368" + } + }, + { + "$id": "636", + "kind": "client", + "name": "PetOperations", + "namespace": "SampleTypeSpec", + "methods": [ + { + "$id": "637", + "kind": "basic", + "name": "updatePetAsPet", + "accessibility": "public", + "apiVersions": [ + "2024-07-16-preview", + "2024-08-16-preview" + ], + "doc": "Update a pet as a pet", + "operation": { + "$id": "638", + "name": "updatePetAsPet", + "resourceName": "PetOperations", + "doc": "Update a pet as a pet", + "accessibility": "public", + "parameters": [ + { + "$id": "639", + "kind": "header", + "name": "contentType", + "serializedName": "Content-Type", + "doc": "Body parameter's content type. Known values are application/json", + "type": { + "$ref": "182" + }, + "isApiVersion": false, + "optional": false, + "isContentType": true, + "scope": "Constant", + "readOnly": false, + "decorators": [], + "crossLanguageDefinitionId": "SampleTypeSpec.PetOperations.updatePetAsPet.contentType" + }, + { + "$id": "640", + "kind": "header", + "name": "accept", + "serializedName": "Accept", + "type": { + "$ref": "184" + }, + "isApiVersion": false, + "optional": false, + "isContentType": false, + "scope": "Constant", + "readOnly": false, + "decorators": [], + "crossLanguageDefinitionId": "SampleTypeSpec.PetOperations.updatePetAsPet.accept" + }, + { + "$id": "641", + "kind": "body", + "name": "pet", + "serializedName": "pet", + "type": { + "$ref": "355" + }, + "isApiVersion": false, + "contentTypes": [ + "application/json" + ], + "defaultContentType": "application/json", + "optional": false, + "scope": "Method", + "decorators": [], + "readOnly": false, + "crossLanguageDefinitionId": "SampleTypeSpec.PetOperations.updatePetAsPet.pet" + } + ], + "responses": [ + { + "statusCodes": [ + 200 + ], + "bodyType": { + "$ref": "355" + }, + "headers": [], + "isErrorResponse": false, + "contentTypes": [ + "application/json" + ] + } + ], + "httpMethod": "PUT", + "uri": "{sampleTypeSpecUrl}", + "path": "/pets/pet/as-pet", + "requestMediaTypes": [ + "application/json" + ], + "bufferResponse": true, + "generateProtocolMethod": true, + "generateConvenienceMethod": true, + "crossLanguageDefinitionId": "SampleTypeSpec.PetOperations.updatePetAsPet", + "decorators": [] + }, + "parameters": [ + { + "$id": "642", + "kind": "method", + "name": "pet", + "serializedName": "pet", + "type": { + "$ref": "355" + }, + "location": "Body", + "isApiVersion": false, + "optional": false, + "scope": "Method", + "crossLanguageDefinitionId": "SampleTypeSpec.PetOperations.updatePetAsPet.pet", + "readOnly": false, + "access": "public", + "decorators": [] + }, + { + "$id": "643", + "kind": "method", + "name": "contentType", + "serializedName": "Content-Type", + "doc": "Body parameter's content type. Known values are application/json", + "type": { + "$ref": "182" + }, + "location": "Header", + "isApiVersion": false, + "optional": false, + "scope": "Constant", + "crossLanguageDefinitionId": "SampleTypeSpec.PetOperations.updatePetAsPet.contentType", + "readOnly": false, + "access": "public", + "decorators": [] + }, + { + "$id": "644", + "kind": "method", + "name": "accept", + "serializedName": "Accept", + "type": { + "$ref": "184" + }, + "location": "Header", + "isApiVersion": false, + "optional": false, + "scope": "Constant", + "crossLanguageDefinitionId": "SampleTypeSpec.PetOperations.updatePetAsPet.accept", + "readOnly": false, + "access": "public", + "decorators": [] + } + ], + "response": { + "type": { + "$ref": "355" + } + }, + "isOverride": false, + "generateConvenient": true, + "generateProtocol": true, + "crossLanguageDefinitionId": "SampleTypeSpec.PetOperations.updatePetAsPet" + }, + { + "$id": "645", + "kind": "basic", + "name": "updateDogAsPet", + "accessibility": "public", + "apiVersions": [ + "2024-07-16-preview", + "2024-08-16-preview" + ], + "doc": "Update a dog as a pet", + "operation": { + "$id": "646", + "name": "updateDogAsPet", + "resourceName": "PetOperations", + "doc": "Update a dog as a pet", + "accessibility": "public", + "parameters": [ + { + "$id": "647", + "kind": "header", + "name": "contentType", + "serializedName": "Content-Type", + "doc": "Body parameter's content type. Known values are application/json", + "type": { + "$ref": "186" + }, + "isApiVersion": false, + "optional": false, + "isContentType": true, + "scope": "Constant", + "readOnly": false, + "decorators": [], + "crossLanguageDefinitionId": "SampleTypeSpec.PetOperations.updateDogAsPet.contentType" + }, + { + "$id": "648", + "kind": "header", + "name": "accept", + "serializedName": "Accept", + "type": { + "$ref": "188" + }, + "isApiVersion": false, + "optional": false, + "isContentType": false, + "scope": "Constant", + "readOnly": false, + "decorators": [], + "crossLanguageDefinitionId": "SampleTypeSpec.PetOperations.updateDogAsPet.accept" + }, + { + "$id": "649", + "kind": "body", + "name": "pet", + "serializedName": "pet", + "type": { + "$ref": "355" + }, + "isApiVersion": false, + "contentTypes": [ + "application/json" + ], + "defaultContentType": "application/json", + "optional": false, + "scope": "Method", + "decorators": [], + "readOnly": false, + "crossLanguageDefinitionId": "SampleTypeSpec.PetOperations.updateDogAsPet.pet" + } + ], + "responses": [ + { + "statusCodes": [ + 200 + ], + "bodyType": { + "$ref": "355" + }, + "headers": [], + "isErrorResponse": false, + "contentTypes": [ + "application/json" + ] + } + ], + "httpMethod": "PUT", + "uri": "{sampleTypeSpecUrl}", + "path": "/pets/dog/as-pet", + "requestMediaTypes": [ + "application/json" + ], + "bufferResponse": true, + "generateProtocolMethod": true, + "generateConvenienceMethod": true, + "crossLanguageDefinitionId": "SampleTypeSpec.PetOperations.updateDogAsPet", + "decorators": [] + }, + "parameters": [ + { + "$id": "650", + "kind": "method", + "name": "pet", + "serializedName": "pet", + "type": { + "$ref": "355" + }, + "location": "Body", + "isApiVersion": false, + "optional": false, + "scope": "Method", + "crossLanguageDefinitionId": "SampleTypeSpec.PetOperations.updateDogAsPet.pet", + "readOnly": false, + "access": "public", + "decorators": [] + }, + { + "$id": "651", + "kind": "method", + "name": "contentType", + "serializedName": "Content-Type", + "doc": "Body parameter's content type. Known values are application/json", + "type": { + "$ref": "186" + }, + "location": "Header", + "isApiVersion": false, + "optional": false, + "scope": "Constant", + "crossLanguageDefinitionId": "SampleTypeSpec.PetOperations.updateDogAsPet.contentType", + "readOnly": false, + "access": "public", + "decorators": [] + }, + { + "$id": "652", + "kind": "method", + "name": "accept", + "serializedName": "Accept", + "type": { + "$ref": "188" + }, + "location": "Header", + "isApiVersion": false, + "optional": false, + "scope": "Constant", + "crossLanguageDefinitionId": "SampleTypeSpec.PetOperations.updateDogAsPet.accept", + "readOnly": false, + "access": "public", + "decorators": [] + } + ], + "response": { + "type": { + "$ref": "355" + } + }, + "isOverride": false, + "generateConvenient": true, + "generateProtocol": true, + "crossLanguageDefinitionId": "SampleTypeSpec.PetOperations.updateDogAsPet" + } + ], + "parameters": [ + { + "$id": "653", + "kind": "endpoint", + "name": "sampleTypeSpecUrl", + "serializedName": "sampleTypeSpecUrl", + "type": { + "$id": "654", + "kind": "url", + "name": "endpoint", + "crossLanguageDefinitionId": "TypeSpec.url" + }, + "isApiVersion": false, + "optional": false, + "scope": "Client", + "isEndpoint": true, + "serverUrlTemplate": "{sampleTypeSpecUrl}", + "skipUrlEncoding": false, + "readOnly": false, + "crossLanguageDefinitionId": "SampleTypeSpec.sampleTypeSpecUrl" + } + ], + "initializedBy": 0, + "decorators": [], + "crossLanguageDefinitionId": "SampleTypeSpec.PetOperations", + "apiVersions": [ + "2024-07-16-preview", + "2024-08-16-preview" + ], + "parent": { + "$ref": "368" + } + }, + { + "$id": "655", + "kind": "client", + "name": "DogOperations", + "namespace": "SampleTypeSpec", + "methods": [ + { + "$id": "656", + "kind": "basic", + "name": "updateDogAsDog", + "accessibility": "public", + "apiVersions": [ + "2024-07-16-preview", + "2024-08-16-preview" + ], + "doc": "Update a dog as a dog", + "operation": { + "$id": "657", + "name": "updateDogAsDog", + "resourceName": "DogOperations", + "doc": "Update a dog as a dog", + "accessibility": "public", + "parameters": [ + { + "$id": "658", + "kind": "header", + "name": "contentType", + "serializedName": "Content-Type", + "doc": "Body parameter's content type. Known values are application/json", + "type": { + "$ref": "190" + }, + "isApiVersion": false, + "optional": false, + "isContentType": true, + "scope": "Constant", + "readOnly": false, + "decorators": [], + "crossLanguageDefinitionId": "SampleTypeSpec.DogOperations.updateDogAsDog.contentType" + }, + { + "$id": "659", + "kind": "header", + "name": "accept", + "serializedName": "Accept", + "type": { + "$ref": "192" + }, + "isApiVersion": false, + "optional": false, + "isContentType": false, + "scope": "Constant", + "readOnly": false, + "decorators": [], + "crossLanguageDefinitionId": "SampleTypeSpec.DogOperations.updateDogAsDog.accept" + }, + { + "$id": "660", + "kind": "body", + "name": "dog", + "serializedName": "dog", + "type": { + "$ref": "359" + }, + "isApiVersion": false, + "contentTypes": [ + "application/json" + ], + "defaultContentType": "application/json", + "optional": false, + "scope": "Method", + "decorators": [], + "readOnly": false, + "crossLanguageDefinitionId": "SampleTypeSpec.DogOperations.updateDogAsDog.dog" + } + ], + "responses": [ + { + "statusCodes": [ + 200 + ], + "bodyType": { + "$ref": "359" + }, + "headers": [], + "isErrorResponse": false, + "contentTypes": [ + "application/json" + ] + } + ], + "httpMethod": "PUT", + "uri": "{sampleTypeSpecUrl}", + "path": "/dogs/dog/as-dog", + "requestMediaTypes": [ + "application/json" + ], + "bufferResponse": true, + "generateProtocolMethod": true, + "generateConvenienceMethod": true, + "crossLanguageDefinitionId": "SampleTypeSpec.DogOperations.updateDogAsDog", + "decorators": [] + }, + "parameters": [ + { + "$id": "661", + "kind": "method", + "name": "dog", + "serializedName": "dog", + "type": { + "$ref": "359" + }, + "location": "Body", + "isApiVersion": false, + "optional": false, + "scope": "Method", + "crossLanguageDefinitionId": "SampleTypeSpec.DogOperations.updateDogAsDog.dog", + "readOnly": false, + "access": "public", + "decorators": [] + }, + { + "$id": "662", + "kind": "method", + "name": "contentType", + "serializedName": "Content-Type", + "doc": "Body parameter's content type. Known values are application/json", + "type": { + "$ref": "190" + }, + "location": "Header", + "isApiVersion": false, + "optional": false, + "scope": "Constant", + "crossLanguageDefinitionId": "SampleTypeSpec.DogOperations.updateDogAsDog.contentType", + "readOnly": false, + "access": "public", + "decorators": [] + }, + { + "$id": "663", + "kind": "method", + "name": "accept", + "serializedName": "Accept", + "type": { + "$ref": "192" + }, + "location": "Header", + "isApiVersion": false, + "optional": false, + "scope": "Constant", + "crossLanguageDefinitionId": "SampleTypeSpec.DogOperations.updateDogAsDog.accept", + "readOnly": false, + "access": "public", + "decorators": [] + } + ], + "response": { + "type": { + "$ref": "359" + } + }, + "isOverride": false, + "generateConvenient": true, + "generateProtocol": true, + "crossLanguageDefinitionId": "SampleTypeSpec.DogOperations.updateDogAsDog" + } + ], + "parameters": [ + { + "$id": "664", + "kind": "endpoint", + "name": "sampleTypeSpecUrl", + "serializedName": "sampleTypeSpecUrl", + "type": { + "$id": "665", + "kind": "url", + "name": "endpoint", + "crossLanguageDefinitionId": "TypeSpec.url" + }, + "isApiVersion": false, + "optional": false, + "scope": "Client", + "isEndpoint": true, + "serverUrlTemplate": "{sampleTypeSpecUrl}", + "skipUrlEncoding": false, + "readOnly": false, + "crossLanguageDefinitionId": "SampleTypeSpec.sampleTypeSpecUrl" + } + ], + "initializedBy": 0, + "decorators": [], + "crossLanguageDefinitionId": "SampleTypeSpec.DogOperations", + "apiVersions": [ + "2024-07-16-preview", + "2024-08-16-preview" + ], + "parent": { + "$ref": "368" + } + }, + { + "$id": "666", + "kind": "client", + "name": "Metrics", + "namespace": "SampleTypeSpec", + "methods": [ + { + "$id": "667", + "kind": "basic", + "name": "getWidgetMetrics", + "accessibility": "public", + "apiVersions": [ + "2024-07-16-preview", + "2024-08-16-preview" + ], + "doc": "Get Widget metrics for given day of week", + "operation": { + "$id": "668", + "name": "getWidgetMetrics", + "resourceName": "Metrics", + "doc": "Get Widget metrics for given day of week", + "accessibility": "public", + "parameters": [ + { + "$id": "669", + "kind": "path", + "name": "day", + "serializedName": "day", + "type": { + "$ref": "57" + }, + "isApiVersion": false, + "explode": false, + "style": "simple", + "allowReserved": false, + "skipUrlEncoding": false, + "optional": false, + "scope": "Method", + "decorators": [], + "readOnly": false, + "crossLanguageDefinitionId": "SampleTypeSpec.Metrics.getWidgetMetrics.day" + }, + { + "$id": "670", + "kind": "header", + "name": "accept", + "serializedName": "Accept", + "type": { + "$ref": "194" + }, + "isApiVersion": false, + "optional": false, + "isContentType": false, + "scope": "Constant", + "readOnly": false, + "decorators": [], + "crossLanguageDefinitionId": "SampleTypeSpec.Metrics.getWidgetMetrics.accept" + } + ], + "responses": [ + { + "statusCodes": [ + 200 + ], + "bodyType": { + "$ref": "363" + }, + "headers": [], + "isErrorResponse": false, + "contentTypes": [ + "application/json" + ] + } + ], + "httpMethod": "GET", + "uri": "{sampleTypeSpecUrl}", + "path": "/metrics/widgets/daysOfWeek/{day}", + "bufferResponse": true, + "generateProtocolMethod": true, + "generateConvenienceMethod": true, + "crossLanguageDefinitionId": "SampleTypeSpec.Metrics.getWidgetMetrics", + "decorators": [] + }, + "parameters": [ + { + "$id": "671", + "kind": "method", + "name": "day", + "serializedName": "day", + "type": { + "$ref": "57" + }, + "location": "Path", + "isApiVersion": false, + "optional": false, + "scope": "Method", + "crossLanguageDefinitionId": "SampleTypeSpec.Metrics.getWidgetMetrics.day", + "readOnly": false, + "access": "public", + "decorators": [] + }, + { + "$id": "672", + "kind": "method", + "name": "accept", + "serializedName": "Accept", + "type": { + "$ref": "194" + }, + "location": "Header", + "isApiVersion": false, + "optional": false, + "scope": "Constant", + "crossLanguageDefinitionId": "SampleTypeSpec.Metrics.getWidgetMetrics.accept", + "readOnly": false, + "access": "public", + "decorators": [] + } + ], + "response": { + "type": { + "$ref": "363" + } + }, + "isOverride": false, + "generateConvenient": true, + "generateProtocol": true, + "crossLanguageDefinitionId": "SampleTypeSpec.Metrics.getWidgetMetrics" + } + ], + "parameters": [ + { + "$id": "673", "kind": "endpoint", "name": "sampleTypeSpecUrl", "serializedName": "sampleTypeSpecUrl", "type": { - "$id": "588", + "$id": "674", "kind": "url", "name": "endpoint", "crossLanguageDefinitionId": "TypeSpec.url" @@ -8117,7 +9443,7 @@ "2024-08-16-preview" ], "parent": { - "$ref": "331" + "$ref": "368" } } ] From e50ab7cd4acbd3a0b0bcdceb7cbcadc66c90ab8f Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Fri, 5 Dec 2025 18:09:35 -0500 Subject: [PATCH 08/40] Upgrade pools (#9009) --- cspell.yaml | 2 -- eng/common/pipelines/templates/variables/image.yml | 10 +++++----- eng/tsp-core/pipelines/jobs/cli/build-tsp-cli.yml | 4 ++-- eng/tsp-core/pipelines/jobs/cli/verify-tsp-cli.yml | 4 ++-- eng/tsp-core/pipelines/publish.yml | 1 + 5 files changed, 10 insertions(+), 11 deletions(-) diff --git a/cspell.yaml b/cspell.yaml index 3d5a5009cdb..98e7cc43a05 100644 --- a/cspell.yaml +++ b/cspell.yaml @@ -142,8 +142,6 @@ words: - lropaging - lstrip - lzutf - - MACVMIMAGE - - MACVMIMAGEM - mday - methodsubscriptionid - mgmt diff --git a/eng/common/pipelines/templates/variables/image.yml b/eng/common/pipelines/templates/variables/image.yml index 8c0b780abc1..87d9439f813 100644 --- a/eng/common/pipelines/templates/variables/image.yml +++ b/eng/common/pipelines/templates/variables/image.yml @@ -17,15 +17,15 @@ variables: - name: LINUXNEXTVMIMAGE value: ubuntu-24.04 - name: LINUXARMVMIMAGE - value: azsdk-pool-mms-mariner-2-arm-1espt + value: azure-linux-3-arm64 - name: WINDOWSVMIMAGE value: windows-2022 - name: WINDOWSARMVMIMAGE value: windows-2022-arm64-1espt - - name: MACVMIMAGE # mac - arm64 - value: macos-latest - - name: MACVMIMAGE13 # mac - x64 - value: macos-13 + - name: MAC_ARM_VM_IMAGE # mac - arm64 + value: macos-latest-internal + - name: MAC_X64_VM_IMAGE # mac - x64 + value: macos-15 # Values required for pool.os field in 1es pipeline templates. Variable form # cannot be used, instead those values must be written directly into pool.os. diff --git a/eng/tsp-core/pipelines/jobs/cli/build-tsp-cli.yml b/eng/tsp-core/pipelines/jobs/cli/build-tsp-cli.yml index 41e79000ca7..da0d39ebed9 100644 --- a/eng/tsp-core/pipelines/jobs/cli/build-tsp-cli.yml +++ b/eng/tsp-core/pipelines/jobs/cli/build-tsp-cli.yml @@ -17,11 +17,11 @@ jobs: hostArchitecture: arm64 ${{ if eq(parameters.platform, 'macos-x64') }}: name: $(MACPOOL) - vmImage: $(MACVMIMAGE13) + vmImage: $(MAC_X64_VM_IMAGE) os: macOS ${{ if eq(parameters.platform, 'macos-arm64') }}: name: $(MACPOOL) - vmImage: $(MACVMIMAGE) + vmImage: $(MAC_ARM_VM_IMAGE) os: macOS ${{ if eq(parameters.platform, 'windows-x64') }}: name: $(WINDOWSPOOL) diff --git a/eng/tsp-core/pipelines/jobs/cli/verify-tsp-cli.yml b/eng/tsp-core/pipelines/jobs/cli/verify-tsp-cli.yml index 566ede09b30..8551b416fd2 100644 --- a/eng/tsp-core/pipelines/jobs/cli/verify-tsp-cli.yml +++ b/eng/tsp-core/pipelines/jobs/cli/verify-tsp-cli.yml @@ -23,11 +23,11 @@ jobs: hostArchitecture: arm64 ${{ if eq(parameters.platform, 'macos-x64') }}: name: $(MACPOOL) - vmImage: $(MACVMIMAGE13) + vmImage: $(MAC_X64_VM_IMAGE) os: macOS ${{ if eq(parameters.platform, 'macos-arm64') }}: name: $(MACPOOL) - vmImage: $(MACVMIMAGE) + vmImage: $(MAC_ARM_VM_IMAGE) os: macOS ${{ if eq(parameters.platform, 'windows-x64') }}: name: $(WINDOWSPOOL) diff --git a/eng/tsp-core/pipelines/publish.yml b/eng/tsp-core/pipelines/publish.yml index ab6e626181d..b2d43f64177 100644 --- a/eng/tsp-core/pipelines/publish.yml +++ b/eng/tsp-core/pipelines/publish.yml @@ -6,6 +6,7 @@ trigger: - main # For patch releases - release/* + - upgrade/pool-images paths: exclude: - packages/http-client-csharp From 7af8f6d1cf2f203237543f234bb255927524dc93 Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Mon, 8 Dec 2025 11:35:41 +0800 Subject: [PATCH 09/40] [Python] Fix serialization name for multipart (#9138) fix https://github.com/microsoft/typespec/issues/9137 Related PR: - [ ] https://github.com/microsoft/typespec/pull/9139 --- ...n-multipart-fix-serialization-name-2025-11-4-7-44-27.md | 7 +++++++ packages/http-client-python/emitter/src/types.ts | 5 ++++- 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 .chronus/changes/python-multipart-fix-serialization-name-2025-11-4-7-44-27.md diff --git a/.chronus/changes/python-multipart-fix-serialization-name-2025-11-4-7-44-27.md b/.chronus/changes/python-multipart-fix-serialization-name-2025-11-4-7-44-27.md new file mode 100644 index 00000000000..d22b2a63f15 --- /dev/null +++ b/.chronus/changes/python-multipart-fix-serialization-name-2025-11-4-7-44-27.md @@ -0,0 +1,7 @@ +--- +changeKind: fix +packages: + - "@typespec/http-client-python" +--- + +Fix serialization name for multipart \ No newline at end of file diff --git a/packages/http-client-python/emitter/src/types.ts b/packages/http-client-python/emitter/src/types.ts index ee7a373ed8f..ffa8fc418df 100644 --- a/packages/http-client-python/emitter/src/types.ts +++ b/packages/http-client-python/emitter/src/types.ts @@ -235,7 +235,10 @@ function emitProperty( } return { clientName: camelToSnakeCase(property.name), - wireName: property.serializationOptions.json?.name ?? property.name, + wireName: + (property.serializationOptions?.multipart + ? property.serializationOptions?.multipart?.name + : property.serializationOptions?.json?.name) ?? property.name, type: getType(context, sourceType), optional: property.optional, description: property.summary ? property.summary : property.doc, From b1176f532e715bde413d3c61d8eb52ef8c7b5dfc Mon Sep 17 00:00:00 2001 From: Weidong Xu Date: Mon, 8 Dec 2025 12:02:57 +0800 Subject: [PATCH 10/40] http-client-java, fix FinalResult model incorrectly removed (#9145) Caused by https://github.com/microsoft/typespec/pull/9109 Happens in mgmt flow, where we clean up unused model. Therefore, when we use FinalResult (instead of Response) model from LRO, we'd need to change this logic too. --- test https://github.com/Azure/autorest.java/pull/3237 https://github.com/Azure/azure-sdk-for-java/pull/47475 (some model get removed, Build pass) --- .../mgmt/transformer/SchemaCleanup.java | 18 +- .../fluent/LroNoBodiesClient.java | 97 ++++++++++ .../implementation/LroNoBodiesClientImpl.java | 180 ++++++++++++++++++ .../implementation/LroNoBodiesImpl.java | 9 + .../models/ActionFinalResult.java | 75 ++++++++ .../models/LroNoBodies.java | 25 +++ ...provider-generated_apiview_properties.json | 6 + ...rmresourceprovider-generated_metadata.json | 2 +- .../java/tsptest/arm/LroResponseTests.java | 29 +++ .../StreamStyleSerializationTests.java | 3 + .../http-client-generator-test/tsp/arm.tsp | 19 ++ packages/http-client-java/package-lock.json | 8 +- 12 files changed, 458 insertions(+), 13 deletions(-) create mode 100644 packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/armresourceprovider/models/ActionFinalResult.java create mode 100644 packages/http-client-java/generator/http-client-generator-test/src/test/java/tsptest/arm/LroResponseTests.java diff --git a/packages/http-client-java/generator/http-client-generator-mgmt/src/main/java/com/microsoft/typespec/http/client/generator/mgmt/transformer/SchemaCleanup.java b/packages/http-client-java/generator/http-client-generator-mgmt/src/main/java/com/microsoft/typespec/http/client/generator/mgmt/transformer/SchemaCleanup.java index b2b170eb015..c66dd3fd88d 100644 --- a/packages/http-client-java/generator/http-client-generator-mgmt/src/main/java/com/microsoft/typespec/http/client/generator/mgmt/transformer/SchemaCleanup.java +++ b/packages/http-client-java/generator/http-client-generator-mgmt/src/main/java/com/microsoft/typespec/http/client/generator/mgmt/transformer/SchemaCleanup.java @@ -108,14 +108,16 @@ private static boolean tryCleanup(CodeModel codeModel, Set javaNamesForP } if (!schemasNotInUse.isEmpty() || !choicesSchemasNotInUse.isEmpty()) { // operation responses - Set responses = codeModel.getOperationGroups() - .stream() - .flatMap(og -> og.getOperations().stream()) - .flatMap(o -> o.getResponses().stream()) - .map(Response::getSchema) - .map(SchemaCleanup::schemaOrElementInCollection) - .filter(Objects::nonNull) - .collect(Collectors.toSet()); + Set responses + = codeModel.getOperationGroups().stream().flatMap(og -> og.getOperations().stream()).flatMap(o -> { + if (o.getLroMetadata() == null) { + // not LRO operation, or it is LRO but not from TypeSpec + return o.getResponses().stream().map(Response::getSchema); + } else { + // if the operation has LroMetadata, SDK will use its FinalResultType + return Stream.of(o.getLroMetadata().getFinalResultType()); + } + }).map(SchemaCleanup::schemaOrElementInCollection).filter(Objects::nonNull).collect(Collectors.toSet()); schemasNotInUse.removeAll(responses); choicesSchemasNotInUse.removeAll(responses); schemasInUse.addAll(responses); diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/armresourceprovider/fluent/LroNoBodiesClient.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/armresourceprovider/fluent/LroNoBodiesClient.java index 91a53f9061a..2bdefd6ca4f 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/armresourceprovider/fluent/LroNoBodiesClient.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/armresourceprovider/fluent/LroNoBodiesClient.java @@ -14,6 +14,7 @@ import java.nio.ByteBuffer; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import tsptest.armresourceprovider.models.ActionFinalResult; import tsptest.armresourceprovider.models.ResourceLroNoBody; /** @@ -126,4 +127,100 @@ ResourceLroNoBody createOrUpdate(String resourceGroupName, String resourceLroNoB @ServiceMethod(returns = ReturnType.SINGLE) ResourceLroNoBody createOrUpdate(String resourceGroupName, String resourceLroNoBodyName, ResourceLroNoBody resource, Context context); + + /** + * A long-running resource action. + * + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param resourceLroNoBodyName The name of the ResourceLroNoBody. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws com.azure.core.management.exception.ManagementException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response body along with {@link Response} on successful completion of {@link Mono}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + Mono>> actionWithResponseAsync(String resourceGroupName, String resourceLroNoBodyName); + + /** + * A long-running resource action. + * + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param resourceLroNoBodyName The name of the ResourceLroNoBody. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws com.azure.core.management.exception.ManagementException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the {@link PollerFlux} for polling of long-running operation. + */ + @ServiceMethod(returns = ReturnType.LONG_RUNNING_OPERATION) + PollerFlux, ActionFinalResult> beginActionAsync(String resourceGroupName, + String resourceLroNoBodyName); + + /** + * A long-running resource action. + * + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param resourceLroNoBodyName The name of the ResourceLroNoBody. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws com.azure.core.management.exception.ManagementException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the {@link SyncPoller} for polling of long-running operation. + */ + @ServiceMethod(returns = ReturnType.LONG_RUNNING_OPERATION) + SyncPoller, ActionFinalResult> beginAction(String resourceGroupName, + String resourceLroNoBodyName); + + /** + * A long-running resource action. + * + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param resourceLroNoBodyName The name of the ResourceLroNoBody. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws com.azure.core.management.exception.ManagementException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the {@link SyncPoller} for polling of long-running operation. + */ + @ServiceMethod(returns = ReturnType.LONG_RUNNING_OPERATION) + SyncPoller, ActionFinalResult> beginAction(String resourceGroupName, + String resourceLroNoBodyName, Context context); + + /** + * A long-running resource action. + * + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param resourceLroNoBodyName The name of the ResourceLroNoBody. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws com.azure.core.management.exception.ManagementException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response body on successful completion of {@link Mono}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + Mono actionAsync(String resourceGroupName, String resourceLroNoBodyName); + + /** + * A long-running resource action. + * + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param resourceLroNoBodyName The name of the ResourceLroNoBody. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws com.azure.core.management.exception.ManagementException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + ActionFinalResult action(String resourceGroupName, String resourceLroNoBodyName); + + /** + * A long-running resource action. + * + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param resourceLroNoBodyName The name of the ResourceLroNoBody. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws com.azure.core.management.exception.ManagementException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + ActionFinalResult action(String resourceGroupName, String resourceLroNoBodyName, Context context); } diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/armresourceprovider/implementation/LroNoBodiesClientImpl.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/armresourceprovider/implementation/LroNoBodiesClientImpl.java index c80c8191c64..4c9b682e39d 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/armresourceprovider/implementation/LroNoBodiesClientImpl.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/armresourceprovider/implementation/LroNoBodiesClientImpl.java @@ -11,6 +11,7 @@ import com.azure.core.annotation.Host; import com.azure.core.annotation.HostParam; import com.azure.core.annotation.PathParam; +import com.azure.core.annotation.Post; import com.azure.core.annotation.Put; import com.azure.core.annotation.QueryParam; import com.azure.core.annotation.ReturnType; @@ -30,6 +31,7 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import tsptest.armresourceprovider.fluent.LroNoBodiesClient; +import tsptest.armresourceprovider.models.ActionFinalResult; import tsptest.armresourceprovider.models.ResourceLroNoBody; /** @@ -85,6 +87,26 @@ Response createOrUpdateSync(@HostParam("endpoint") String endpoint, @PathParam("resourceLroNoBodyName") String resourceLroNoBodyName, @HeaderParam("Content-Type") String contentType, @BodyParam("application/json") ResourceLroNoBody resource, Context context); + + @Headers({ "Content-Type: application/json" }) + @Post("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/TspTest.ArmResourceProvider/resourceLroNoBody/{resourceLroNoBodyName}/action") + @ExpectedResponses({ 200, 202 }) + @UnexpectedResponseExceptionType(ManagementException.class) + Mono>> action(@HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, @PathParam("subscriptionId") String subscriptionId, + @PathParam("resourceGroupName") String resourceGroupName, + @PathParam("resourceLroNoBodyName") String resourceLroNoBodyName, @HeaderParam("Accept") String accept, + Context context); + + @Headers({ "Content-Type: application/json" }) + @Post("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/TspTest.ArmResourceProvider/resourceLroNoBody/{resourceLroNoBodyName}/action") + @ExpectedResponses({ 200, 202 }) + @UnexpectedResponseExceptionType(ManagementException.class) + Response actionSync(@HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, @PathParam("subscriptionId") String subscriptionId, + @PathParam("resourceGroupName") String resourceGroupName, + @PathParam("resourceLroNoBodyName") String resourceLroNoBodyName, @HeaderParam("Accept") String accept, + Context context); } /** @@ -261,4 +283,162 @@ public ResourceLroNoBody createOrUpdate(String resourceGroupName, String resourc ResourceLroNoBody resource, Context context) { return beginCreateOrUpdate(resourceGroupName, resourceLroNoBodyName, resource, context).getFinalResult(); } + + /** + * A long-running resource action. + * + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param resourceLroNoBodyName The name of the ResourceLroNoBody. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws ManagementException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response body along with {@link Response} on successful completion of {@link Mono}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono>> actionWithResponseAsync(String resourceGroupName, + String resourceLroNoBodyName) { + final String accept = "application/json"; + return FluxUtil + .withContext(context -> service.action(this.client.getEndpoint(), this.client.getApiVersion(), + this.client.getSubscriptionId(), resourceGroupName, resourceLroNoBodyName, accept, context)) + .contextWrite(context -> context.putAll(FluxUtil.toReactorContext(this.client.getContext()).readOnly())); + } + + /** + * A long-running resource action. + * + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param resourceLroNoBodyName The name of the ResourceLroNoBody. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws ManagementException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response body along with {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + private Response actionWithResponse(String resourceGroupName, String resourceLroNoBodyName) { + final String accept = "application/json"; + return service.actionSync(this.client.getEndpoint(), this.client.getApiVersion(), + this.client.getSubscriptionId(), resourceGroupName, resourceLroNoBodyName, accept, Context.NONE); + } + + /** + * A long-running resource action. + * + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param resourceLroNoBodyName The name of the ResourceLroNoBody. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws ManagementException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response body along with {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + private Response actionWithResponse(String resourceGroupName, String resourceLroNoBodyName, + Context context) { + final String accept = "application/json"; + return service.actionSync(this.client.getEndpoint(), this.client.getApiVersion(), + this.client.getSubscriptionId(), resourceGroupName, resourceLroNoBodyName, accept, context); + } + + /** + * A long-running resource action. + * + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param resourceLroNoBodyName The name of the ResourceLroNoBody. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws ManagementException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the {@link PollerFlux} for polling of long-running operation. + */ + @ServiceMethod(returns = ReturnType.LONG_RUNNING_OPERATION) + public PollerFlux, ActionFinalResult> beginActionAsync(String resourceGroupName, + String resourceLroNoBodyName) { + Mono>> mono = actionWithResponseAsync(resourceGroupName, resourceLroNoBodyName); + return this.client.getLroResult(mono, this.client.getHttpPipeline(), + ActionFinalResult.class, ActionFinalResult.class, this.client.getContext()); + } + + /** + * A long-running resource action. + * + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param resourceLroNoBodyName The name of the ResourceLroNoBody. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws ManagementException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the {@link SyncPoller} for polling of long-running operation. + */ + @ServiceMethod(returns = ReturnType.LONG_RUNNING_OPERATION) + public SyncPoller, ActionFinalResult> beginAction(String resourceGroupName, + String resourceLroNoBodyName) { + Response response = actionWithResponse(resourceGroupName, resourceLroNoBodyName); + return this.client.getLroResult(response, ActionFinalResult.class, + ActionFinalResult.class, Context.NONE); + } + + /** + * A long-running resource action. + * + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param resourceLroNoBodyName The name of the ResourceLroNoBody. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws ManagementException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the {@link SyncPoller} for polling of long-running operation. + */ + @ServiceMethod(returns = ReturnType.LONG_RUNNING_OPERATION) + public SyncPoller, ActionFinalResult> beginAction(String resourceGroupName, + String resourceLroNoBodyName, Context context) { + Response response = actionWithResponse(resourceGroupName, resourceLroNoBodyName, context); + return this.client.getLroResult(response, ActionFinalResult.class, + ActionFinalResult.class, context); + } + + /** + * A long-running resource action. + * + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param resourceLroNoBodyName The name of the ResourceLroNoBody. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws ManagementException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response body on successful completion of {@link Mono}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono actionAsync(String resourceGroupName, String resourceLroNoBodyName) { + return beginActionAsync(resourceGroupName, resourceLroNoBodyName).last() + .flatMap(this.client::getLroFinalResultOrError); + } + + /** + * A long-running resource action. + * + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param resourceLroNoBodyName The name of the ResourceLroNoBody. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws ManagementException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public ActionFinalResult action(String resourceGroupName, String resourceLroNoBodyName) { + return beginAction(resourceGroupName, resourceLroNoBodyName).getFinalResult(); + } + + /** + * A long-running resource action. + * + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param resourceLroNoBodyName The name of the ResourceLroNoBody. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws ManagementException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public ActionFinalResult action(String resourceGroupName, String resourceLroNoBodyName, Context context) { + return beginAction(resourceGroupName, resourceLroNoBodyName, context).getFinalResult(); + } } diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/armresourceprovider/implementation/LroNoBodiesImpl.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/armresourceprovider/implementation/LroNoBodiesImpl.java index 5945af22c14..7a5929e9328 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/armresourceprovider/implementation/LroNoBodiesImpl.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/armresourceprovider/implementation/LroNoBodiesImpl.java @@ -7,6 +7,7 @@ import com.azure.core.util.Context; import com.azure.core.util.logging.ClientLogger; import tsptest.armresourceprovider.fluent.LroNoBodiesClient; +import tsptest.armresourceprovider.models.ActionFinalResult; import tsptest.armresourceprovider.models.LroNoBodies; import tsptest.armresourceprovider.models.ResourceLroNoBody; @@ -33,6 +34,14 @@ public ResourceLroNoBody createOrUpdate(String resourceGroupName, String resourc return this.serviceClient().createOrUpdate(resourceGroupName, resourceLroNoBodyName, resource, context); } + public ActionFinalResult action(String resourceGroupName, String resourceLroNoBodyName) { + return this.serviceClient().action(resourceGroupName, resourceLroNoBodyName); + } + + public ActionFinalResult action(String resourceGroupName, String resourceLroNoBodyName, Context context) { + return this.serviceClient().action(resourceGroupName, resourceLroNoBodyName, context); + } + private LroNoBodiesClient serviceClient() { return this.innerClient; } diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/armresourceprovider/models/ActionFinalResult.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/armresourceprovider/models/ActionFinalResult.java new file mode 100644 index 00000000000..270046ccb13 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/armresourceprovider/models/ActionFinalResult.java @@ -0,0 +1,75 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package tsptest.armresourceprovider.models; + +import com.azure.core.annotation.Immutable; +import com.azure.json.JsonReader; +import com.azure.json.JsonSerializable; +import com.azure.json.JsonToken; +import com.azure.json.JsonWriter; +import java.io.IOException; + +/** + * The ActionFinalResult model. + */ +@Immutable +public final class ActionFinalResult implements JsonSerializable { + /* + * The result property. + */ + private String result; + + /** + * Creates an instance of ActionFinalResult class. + */ + private ActionFinalResult() { + } + + /** + * Get the result property: The result property. + * + * @return the result value. + */ + public String result() { + return this.result; + } + + /** + * {@inheritDoc} + */ + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + jsonWriter.writeStringField("result", this.result); + return jsonWriter.writeEndObject(); + } + + /** + * Reads an instance of ActionFinalResult from the JsonReader. + * + * @param jsonReader The JsonReader being read. + * @return An instance of ActionFinalResult if the JsonReader was pointing to an instance of it, or null if it was + * pointing to JSON null. + * @throws IllegalStateException If the deserialized JSON object was missing any required properties. + * @throws IOException If an error occurs while reading the ActionFinalResult. + */ + public static ActionFinalResult fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject(reader -> { + ActionFinalResult deserializedActionFinalResult = new ActionFinalResult(); + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("result".equals(fieldName)) { + deserializedActionFinalResult.result = reader.getString(); + } else { + reader.skipChildren(); + } + } + + return deserializedActionFinalResult; + }); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/armresourceprovider/models/LroNoBodies.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/armresourceprovider/models/LroNoBodies.java index 975db880ef8..68f73d0a5e5 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/armresourceprovider/models/LroNoBodies.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/tsptest/armresourceprovider/models/LroNoBodies.java @@ -38,4 +38,29 @@ ResourceLroNoBody createOrUpdate(String resourceGroupName, String resourceLroNoB */ ResourceLroNoBody createOrUpdate(String resourceGroupName, String resourceLroNoBodyName, ResourceLroNoBody resource, Context context); + + /** + * A long-running resource action. + * + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param resourceLroNoBodyName The name of the ResourceLroNoBody. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws com.azure.core.management.exception.ManagementException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + ActionFinalResult action(String resourceGroupName, String resourceLroNoBodyName); + + /** + * A long-running resource action. + * + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param resourceLroNoBodyName The name of the ResourceLroNoBody. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws com.azure.core.management.exception.ManagementException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + ActionFinalResult action(String resourceGroupName, String resourceLroNoBodyName, Context context); } diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/azure-resourcemanager-armresourceprovider-generated_apiview_properties.json b/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/azure-resourcemanager-armresourceprovider-generated_apiview_properties.json index b3635132152..f3403663ed7 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/azure-resourcemanager-armresourceprovider-generated_apiview_properties.json +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/azure-resourcemanager-armresourceprovider-generated_apiview_properties.json @@ -67,6 +67,11 @@ "tsptest.armresourceprovider.fluent.ImmutableResourceModelsClient.createOrUpdateAsync": "TspTest.ArmResourceProvider.ImmutableResourceModel.createOrUpdate", "tsptest.armresourceprovider.fluent.ImmutableResourceModelsClient.createOrUpdateWithResponseAsync": "TspTest.ArmResourceProvider.ImmutableResourceModel.createOrUpdate", "tsptest.armresourceprovider.fluent.LroNoBodiesClient": "TspTest.ArmResourceProvider.LroNoBody", + "tsptest.armresourceprovider.fluent.LroNoBodiesClient.action": "TspTest.ArmResourceProvider.LroNoBody.action", + "tsptest.armresourceprovider.fluent.LroNoBodiesClient.actionAsync": "TspTest.ArmResourceProvider.LroNoBody.action", + "tsptest.armresourceprovider.fluent.LroNoBodiesClient.actionWithResponseAsync": "TspTest.ArmResourceProvider.LroNoBody.action", + "tsptest.armresourceprovider.fluent.LroNoBodiesClient.beginAction": "TspTest.ArmResourceProvider.LroNoBody.action", + "tsptest.armresourceprovider.fluent.LroNoBodiesClient.beginActionAsync": "TspTest.ArmResourceProvider.LroNoBody.action", "tsptest.armresourceprovider.fluent.LroNoBodiesClient.beginCreateOrUpdate": "TspTest.ArmResourceProvider.LroNoBody.createOrUpdate", "tsptest.armresourceprovider.fluent.LroNoBodiesClient.beginCreateOrUpdateAsync": "TspTest.ArmResourceProvider.LroNoBody.createOrUpdate", "tsptest.armresourceprovider.fluent.LroNoBodiesClient.createOrUpdate": "TspTest.ArmResourceProvider.LroNoBody.createOrUpdate", @@ -142,6 +147,7 @@ "tsptest.armresourceprovider.implementation.models.ChildResourceListResult": "TspTest.ArmResourceProvider.ChildResourceListResult", "tsptest.armresourceprovider.implementation.models.OperationListResult": "Azure.ResourceManager.CommonTypes.OperationListResult", "tsptest.armresourceprovider.implementation.models.ResourceListResult": "Azure.ResourceManager.ResourceListResult", + "tsptest.armresourceprovider.models.ActionFinalResult": "TspTest.ArmResourceProvider.ActionFinalResult", "tsptest.armresourceprovider.models.ActionType": "Azure.ResourceManager.CommonTypes.ActionType", "tsptest.armresourceprovider.models.AnonymousEmptyModel": "TspTest.ArmResourceProvider.CustomTemplateResourceProperties.anonymousEmptyModel.anonymous", "tsptest.armresourceprovider.models.ChildExtensionResourceProperties": "TspTest.ArmResourceProvider.ChildExtensionResourceProperties", diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/azure-resourcemanager-armresourceprovider-generated_metadata.json b/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/azure-resourcemanager-armresourceprovider-generated_metadata.json index 57656c63ac5..89702dc97a1 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/azure-resourcemanager-armresourceprovider-generated_metadata.json +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/azure-resourcemanager-armresourceprovider-generated_metadata.json @@ -1 +1 @@ -{"flavor":"Azure","apiVersion":"2023-11-01","crossLanguageDefinitions":{"tsptest.armresourceprovider.fluent.ArmClient":"TspTest.ArmResourceProvider","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient":"TspTest.ArmResourceProvider.ChildExtensionResourceInterface","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.beginCreateOrUpdate":"Azure.ResourceManager.ChildExtensionResourceInterface.createOrUpdate","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.beginCreateOrUpdateAsync":"Azure.ResourceManager.ChildExtensionResourceInterface.createOrUpdate","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.beginDelete":"Azure.ResourceManager.ChildExtensionResourceInterface.delete","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.beginDeleteAsync":"Azure.ResourceManager.ChildExtensionResourceInterface.delete","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.createOrUpdate":"Azure.ResourceManager.ChildExtensionResourceInterface.createOrUpdate","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.createOrUpdateAsync":"Azure.ResourceManager.ChildExtensionResourceInterface.createOrUpdate","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.createOrUpdateWithResponseAsync":"Azure.ResourceManager.ChildExtensionResourceInterface.createOrUpdate","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.delete":"Azure.ResourceManager.ChildExtensionResourceInterface.delete","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.deleteAsync":"Azure.ResourceManager.ChildExtensionResourceInterface.delete","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.deleteWithResponseAsync":"Azure.ResourceManager.ChildExtensionResourceInterface.delete","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.get":"Azure.ResourceManager.ChildExtensionResourceInterface.get","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.getAsync":"Azure.ResourceManager.ChildExtensionResourceInterface.get","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.getWithResponse":"Azure.ResourceManager.ChildExtensionResourceInterface.get","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.getWithResponseAsync":"Azure.ResourceManager.ChildExtensionResourceInterface.get","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.listByTopLevelArmResource":"Azure.ResourceManager.ChildExtensionResourceInterface.listByTopLevelArmResource","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.listByTopLevelArmResourceAsync":"Azure.ResourceManager.ChildExtensionResourceInterface.listByTopLevelArmResource","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.update":"Azure.ResourceManager.ChildExtensionResourceInterface.update","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.updateAsync":"Azure.ResourceManager.ChildExtensionResourceInterface.update","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.updateWithResponse":"Azure.ResourceManager.ChildExtensionResourceInterface.update","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.updateWithResponseAsync":"Azure.ResourceManager.ChildExtensionResourceInterface.update","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient":"TspTest.ArmResourceProvider.ChildResourcesInterface","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.actionWithoutBody":"TspTest.ArmResourceProvider.ChildResourcesInterface.actionWithoutBody","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.actionWithoutBodyAsync":"TspTest.ArmResourceProvider.ChildResourcesInterface.actionWithoutBody","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.actionWithoutBodyWithResponseAsync":"TspTest.ArmResourceProvider.ChildResourcesInterface.actionWithoutBody","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.beginActionWithoutBody":"TspTest.ArmResourceProvider.ChildResourcesInterface.actionWithoutBody","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.beginActionWithoutBodyAsync":"TspTest.ArmResourceProvider.ChildResourcesInterface.actionWithoutBody","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.beginCreateOrUpdate":"Azure.ResourceManager.ChildResourcesInterface.createOrUpdate","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.beginCreateOrUpdateAsync":"Azure.ResourceManager.ChildResourcesInterface.createOrUpdate","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.beginDelete":"Azure.ResourceManager.ChildResourcesInterface.delete","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.beginDeleteAsync":"Azure.ResourceManager.ChildResourcesInterface.delete","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.createOrUpdate":"Azure.ResourceManager.ChildResourcesInterface.createOrUpdate","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.createOrUpdateAsync":"Azure.ResourceManager.ChildResourcesInterface.createOrUpdate","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.createOrUpdateWithResponseAsync":"Azure.ResourceManager.ChildResourcesInterface.createOrUpdate","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.delete":"Azure.ResourceManager.ChildResourcesInterface.delete","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.deleteAsync":"Azure.ResourceManager.ChildResourcesInterface.delete","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.deleteWithResponseAsync":"Azure.ResourceManager.ChildResourcesInterface.delete","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.get":"Azure.ResourceManager.ChildResourcesInterface.get","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.getAsync":"Azure.ResourceManager.ChildResourcesInterface.get","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.getWithResponse":"Azure.ResourceManager.ChildResourcesInterface.get","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.getWithResponseAsync":"Azure.ResourceManager.ChildResourcesInterface.get","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.listByTopLevelArmResource":"TspTest.ArmResourceProvider.ChildResourcesInterface.listByTopLevelArmResource","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.listByTopLevelArmResourceAsync":"TspTest.ArmResourceProvider.ChildResourcesInterface.listByTopLevelArmResource","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.update":"Azure.ResourceManager.ChildResourcesInterface.update","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.updateAsync":"Azure.ResourceManager.ChildResourcesInterface.update","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.updateWithResponse":"Azure.ResourceManager.ChildResourcesInterface.update","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.updateWithResponseAsync":"Azure.ResourceManager.ChildResourcesInterface.update","tsptest.armresourceprovider.fluent.CustomTemplateResourceInterfacesClient":"TspTest.ArmResourceProvider.CustomTemplateResourceInterface","tsptest.armresourceprovider.fluent.CustomTemplateResourceInterfacesClient.beginCreateOrUpdate":"Azure.ResourceManager.CustomTemplateResourceInterface.createOrUpdate","tsptest.armresourceprovider.fluent.CustomTemplateResourceInterfacesClient.beginCreateOrUpdateAsync":"Azure.ResourceManager.CustomTemplateResourceInterface.createOrUpdate","tsptest.armresourceprovider.fluent.CustomTemplateResourceInterfacesClient.beginUpdateLongRunning":"TspTest.ArmResourceProvider.CustomTemplateResourceInterface.updateLongRunning","tsptest.armresourceprovider.fluent.CustomTemplateResourceInterfacesClient.beginUpdateLongRunningAsync":"TspTest.ArmResourceProvider.CustomTemplateResourceInterface.updateLongRunning","tsptest.armresourceprovider.fluent.CustomTemplateResourceInterfacesClient.createOrUpdate":"Azure.ResourceManager.CustomTemplateResourceInterface.createOrUpdate","tsptest.armresourceprovider.fluent.CustomTemplateResourceInterfacesClient.createOrUpdateAsync":"Azure.ResourceManager.CustomTemplateResourceInterface.createOrUpdate","tsptest.armresourceprovider.fluent.CustomTemplateResourceInterfacesClient.createOrUpdateWithResponseAsync":"Azure.ResourceManager.CustomTemplateResourceInterface.createOrUpdate","tsptest.armresourceprovider.fluent.CustomTemplateResourceInterfacesClient.updateLongRunning":"TspTest.ArmResourceProvider.CustomTemplateResourceInterface.updateLongRunning","tsptest.armresourceprovider.fluent.CustomTemplateResourceInterfacesClient.updateLongRunningAsync":"TspTest.ArmResourceProvider.CustomTemplateResourceInterface.updateLongRunning","tsptest.armresourceprovider.fluent.CustomTemplateResourceInterfacesClient.updateLongRunningWithResponseAsync":"TspTest.ArmResourceProvider.CustomTemplateResourceInterface.updateLongRunning","tsptest.armresourceprovider.fluent.ImmutableResourceModelsClient":"TspTest.ArmResourceProvider.ImmutableResourceModel","tsptest.armresourceprovider.fluent.ImmutableResourceModelsClient.beginCreateOrUpdate":"TspTest.ArmResourceProvider.ImmutableResourceModel.createOrUpdate","tsptest.armresourceprovider.fluent.ImmutableResourceModelsClient.beginCreateOrUpdateAsync":"TspTest.ArmResourceProvider.ImmutableResourceModel.createOrUpdate","tsptest.armresourceprovider.fluent.ImmutableResourceModelsClient.createOrUpdate":"TspTest.ArmResourceProvider.ImmutableResourceModel.createOrUpdate","tsptest.armresourceprovider.fluent.ImmutableResourceModelsClient.createOrUpdateAsync":"TspTest.ArmResourceProvider.ImmutableResourceModel.createOrUpdate","tsptest.armresourceprovider.fluent.ImmutableResourceModelsClient.createOrUpdateWithResponseAsync":"TspTest.ArmResourceProvider.ImmutableResourceModel.createOrUpdate","tsptest.armresourceprovider.fluent.LroNoBodiesClient":"TspTest.ArmResourceProvider.LroNoBody","tsptest.armresourceprovider.fluent.LroNoBodiesClient.beginCreateOrUpdate":"TspTest.ArmResourceProvider.LroNoBody.createOrUpdate","tsptest.armresourceprovider.fluent.LroNoBodiesClient.beginCreateOrUpdateAsync":"TspTest.ArmResourceProvider.LroNoBody.createOrUpdate","tsptest.armresourceprovider.fluent.LroNoBodiesClient.createOrUpdate":"TspTest.ArmResourceProvider.LroNoBody.createOrUpdate","tsptest.armresourceprovider.fluent.LroNoBodiesClient.createOrUpdateAsync":"TspTest.ArmResourceProvider.LroNoBody.createOrUpdate","tsptest.armresourceprovider.fluent.LroNoBodiesClient.createOrUpdateWithResponseAsync":"TspTest.ArmResourceProvider.LroNoBody.createOrUpdate","tsptest.armresourceprovider.fluent.ManagedMaintenanceWindowStatusOperationsClient":"TspTest.ArmResourceProvider.ManagedMaintenanceWindowStatus","tsptest.armresourceprovider.fluent.ManagedMaintenanceWindowStatusOperationsClient.beginDelete":"TspTest.ArmResourceProvider.ManagedMaintenanceWindowStatus.delete","tsptest.armresourceprovider.fluent.ManagedMaintenanceWindowStatusOperationsClient.beginDeleteAsync":"TspTest.ArmResourceProvider.ManagedMaintenanceWindowStatus.delete","tsptest.armresourceprovider.fluent.ManagedMaintenanceWindowStatusOperationsClient.delete":"TspTest.ArmResourceProvider.ManagedMaintenanceWindowStatus.delete","tsptest.armresourceprovider.fluent.ManagedMaintenanceWindowStatusOperationsClient.deleteAsync":"TspTest.ArmResourceProvider.ManagedMaintenanceWindowStatus.delete","tsptest.armresourceprovider.fluent.ManagedMaintenanceWindowStatusOperationsClient.deleteWithResponseAsync":"TspTest.ArmResourceProvider.ManagedMaintenanceWindowStatus.delete","tsptest.armresourceprovider.fluent.ManagedMaintenanceWindowStatusOperationsClient.getByResourceGroup":"TspTest.ArmResourceProvider.ManagedMaintenanceWindowStatus.get","tsptest.armresourceprovider.fluent.ManagedMaintenanceWindowStatusOperationsClient.getByResourceGroupAsync":"TspTest.ArmResourceProvider.ManagedMaintenanceWindowStatus.get","tsptest.armresourceprovider.fluent.ManagedMaintenanceWindowStatusOperationsClient.getByResourceGroupWithResponse":"TspTest.ArmResourceProvider.ManagedMaintenanceWindowStatus.get","tsptest.armresourceprovider.fluent.ManagedMaintenanceWindowStatusOperationsClient.getByResourceGroupWithResponseAsync":"TspTest.ArmResourceProvider.ManagedMaintenanceWindowStatus.get","tsptest.armresourceprovider.fluent.ModelInterfaceSameNamesClient":"TspTest.ArmResourceProvider.ModelInterfaceSameName","tsptest.armresourceprovider.fluent.ModelInterfaceSameNamesClient.delete":"TspTest.ArmResourceProvider.ModelInterfaceSameName.delete","tsptest.armresourceprovider.fluent.ModelInterfaceSameNamesClient.deleteAsync":"TspTest.ArmResourceProvider.ModelInterfaceSameName.delete","tsptest.armresourceprovider.fluent.ModelInterfaceSameNamesClient.deleteWithResponse":"TspTest.ArmResourceProvider.ModelInterfaceSameName.delete","tsptest.armresourceprovider.fluent.ModelInterfaceSameNamesClient.deleteWithResponseAsync":"TspTest.ArmResourceProvider.ModelInterfaceSameName.delete","tsptest.armresourceprovider.fluent.ModelInterfaceSameNamesClient.getByResourceGroup":"TspTest.ArmResourceProvider.ModelInterfaceSameName.get","tsptest.armresourceprovider.fluent.ModelInterfaceSameNamesClient.getByResourceGroupAsync":"TspTest.ArmResourceProvider.ModelInterfaceSameName.get","tsptest.armresourceprovider.fluent.ModelInterfaceSameNamesClient.getByResourceGroupWithResponse":"TspTest.ArmResourceProvider.ModelInterfaceSameName.get","tsptest.armresourceprovider.fluent.ModelInterfaceSameNamesClient.getByResourceGroupWithResponseAsync":"TspTest.ArmResourceProvider.ModelInterfaceSameName.get","tsptest.armresourceprovider.fluent.OperationsClient":"TspTest.ArmResourceProvider.Operations","tsptest.armresourceprovider.fluent.OperationsClient.list":"Azure.ResourceManager.Operations.list","tsptest.armresourceprovider.fluent.OperationsClient.listAsync":"Azure.ResourceManager.Operations.list","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient":"TspTest.ArmResourceProvider.TopLevelArmResourceInterface","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.action":"TspTest.ArmResourceProvider.TopLevelArmResourceInterface.action","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.actionAsync":"TspTest.ArmResourceProvider.TopLevelArmResourceInterface.action","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.actionWithResponseAsync":"TspTest.ArmResourceProvider.TopLevelArmResourceInterface.action","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.beginAction":"TspTest.ArmResourceProvider.TopLevelArmResourceInterface.action","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.beginActionAsync":"TspTest.ArmResourceProvider.TopLevelArmResourceInterface.action","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.beginCreateOrUpdate":"Azure.ResourceManager.TopLevelArmResourceInterface.createOrUpdate","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.beginCreateOrUpdateAsync":"Azure.ResourceManager.TopLevelArmResourceInterface.createOrUpdate","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.beginDelete":"Azure.ResourceManager.TopLevelArmResourceInterface.delete","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.beginDeleteAsync":"Azure.ResourceManager.TopLevelArmResourceInterface.delete","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.createOrUpdate":"Azure.ResourceManager.TopLevelArmResourceInterface.createOrUpdate","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.createOrUpdateAsync":"Azure.ResourceManager.TopLevelArmResourceInterface.createOrUpdate","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.createOrUpdateWithResponseAsync":"Azure.ResourceManager.TopLevelArmResourceInterface.createOrUpdate","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.delete":"Azure.ResourceManager.TopLevelArmResourceInterface.delete","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.deleteAsync":"Azure.ResourceManager.TopLevelArmResourceInterface.delete","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.deleteWithResponseAsync":"Azure.ResourceManager.TopLevelArmResourceInterface.delete","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.getByResourceGroup":"Azure.ResourceManager.TopLevelArmResourceInterface.get","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.getByResourceGroupAsync":"Azure.ResourceManager.TopLevelArmResourceInterface.get","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.getByResourceGroupWithResponse":"Azure.ResourceManager.TopLevelArmResourceInterface.get","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.getByResourceGroupWithResponseAsync":"Azure.ResourceManager.TopLevelArmResourceInterface.get","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.list":"Azure.ResourceManager.TopLevelArmResourceInterface.listBySubscription","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.listAsync":"Azure.ResourceManager.TopLevelArmResourceInterface.listBySubscription","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.listByResourceGroup":"Azure.ResourceManager.TopLevelArmResourceInterface.listByResourceGroup","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.listByResourceGroupAsync":"Azure.ResourceManager.TopLevelArmResourceInterface.listByResourceGroup","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.update":"Azure.ResourceManager.TopLevelArmResourceInterface.update","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.updateAsync":"Azure.ResourceManager.TopLevelArmResourceInterface.update","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.updateWithResponse":"Azure.ResourceManager.TopLevelArmResourceInterface.update","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.updateWithResponseAsync":"Azure.ResourceManager.TopLevelArmResourceInterface.update","tsptest.armresourceprovider.fluent.models.ChildExtensionResourceInner":"TspTest.ArmResourceProvider.ChildExtensionResource","tsptest.armresourceprovider.fluent.models.ChildResourceInner":"TspTest.ArmResourceProvider.ChildResource","tsptest.armresourceprovider.fluent.models.ChildResourceProperties":"TspTest.ArmResourceProvider.ChildResourceProperties","tsptest.armresourceprovider.fluent.models.CustomTemplateResourceInner":"TspTest.ArmResourceProvider.CustomTemplateResource","tsptest.armresourceprovider.fluent.models.CustomTemplateResourceProperties":"TspTest.ArmResourceProvider.CustomTemplateResourceProperties","tsptest.armresourceprovider.fluent.models.ManagedMaintenanceWindowStatusContentProperties":"TspTest.ArmResourceProvider.ManagedMaintenanceWindowStatusContentProperties","tsptest.armresourceprovider.fluent.models.ManagedMaintenanceWindowStatusInner":"TspTest.ArmResourceProvider.ManagedMaintenanceWindowStatusContent","tsptest.armresourceprovider.fluent.models.ModelInterfaceDifferentNameProperties":"TspTest.ArmResourceProvider.ModelInterfaceDifferentNameProperties","tsptest.armresourceprovider.fluent.models.ModelInterfaceSameNameInner":"TspTest.ArmResourceProvider.ModelInterfaceDifferentName","tsptest.armresourceprovider.fluent.models.OperationInner":"Azure.ResourceManager.CommonTypes.Operation","tsptest.armresourceprovider.fluent.models.ResourceLroNoBodyProperties":"TspTest.ArmResourceProvider.ResourceLroNoBodyProperties","tsptest.armresourceprovider.fluent.models.ResultInner":"TspTest.ArmResourceProvider.Result","tsptest.armresourceprovider.fluent.models.TopLevelArmResourceInner":"TspTest.ArmResourceProvider.TopLevelArmResource","tsptest.armresourceprovider.fluent.models.TopLevelArmResourceProperties":"TspTest.ArmResourceProvider.TopLevelArmResourceProperties","tsptest.armresourceprovider.fluent.models.TopLevelArmResourceUpdateProperties":"Azure.ResourceManager.Foundations.ResourceUpdateModelProperties","tsptest.armresourceprovider.implementation.ArmClientBuilder":"TspTest.ArmResourceProvider","tsptest.armresourceprovider.implementation.models.ChildExtensionResourceListResult":"Azure.ResourceManager.ResourceListResult","tsptest.armresourceprovider.implementation.models.ChildResourceListResult":"TspTest.ArmResourceProvider.ChildResourceListResult","tsptest.armresourceprovider.implementation.models.OperationListResult":"Azure.ResourceManager.CommonTypes.OperationListResult","tsptest.armresourceprovider.implementation.models.ResourceListResult":"Azure.ResourceManager.ResourceListResult","tsptest.armresourceprovider.models.ActionType":"Azure.ResourceManager.CommonTypes.ActionType","tsptest.armresourceprovider.models.AnonymousEmptyModel":"TspTest.ArmResourceProvider.CustomTemplateResourceProperties.anonymousEmptyModel.anonymous","tsptest.armresourceprovider.models.ChildExtensionResourceProperties":"TspTest.ArmResourceProvider.ChildExtensionResourceProperties","tsptest.armresourceprovider.models.ChildExtensionResourceUpdate":"Azure.ResourceManager.Foundations.ResourceUpdateModel","tsptest.armresourceprovider.models.ChildResourceUpdate":"Azure.ResourceManager.Foundations.ResourceUpdateModel","tsptest.armresourceprovider.models.CustomTemplateResourcePatch":"TspTest.ArmResourceProvider.CustomTemplateResourcePatch","tsptest.armresourceprovider.models.Dog":"TspTest.ArmResourceProvider.Dog","tsptest.armresourceprovider.models.DogKind":"TspTest.ArmResourceProvider.DogKind","tsptest.armresourceprovider.models.EmptyModel":"TspTest.ArmResourceProvider.EmptyModel","tsptest.armresourceprovider.models.Golden":"TspTest.ArmResourceProvider.Golden","tsptest.armresourceprovider.models.ManagedServiceIdentity":"Azure.ResourceManager.CommonTypes.ManagedServiceIdentity","tsptest.armresourceprovider.models.ManagedServiceIdentityType":"Azure.ResourceManager.CommonTypes.ManagedServiceIdentityType","tsptest.armresourceprovider.models.NginxConfigurationRequest":"TspTest.ArmResourceProvider.NginxConfigurationRequest","tsptest.armresourceprovider.models.NginxConfigurationResponse":"TspTest.ArmResourceProvider.NginxConfigurationResponse","tsptest.armresourceprovider.models.NginxConfigurationResponseProperties":"TspTest.ArmResourceProvider.NginxConfigurationResponseProperties","tsptest.armresourceprovider.models.OperationDisplay":"Azure.ResourceManager.CommonTypes.OperationDisplay","tsptest.armresourceprovider.models.Origin":"Azure.ResourceManager.CommonTypes.Origin","tsptest.armresourceprovider.models.PriorityModel":"TspTest.ArmResourceProvider.PriorityModel","tsptest.armresourceprovider.models.ProvisioningState":"TspTest.ArmResourceProvider.ProvisioningState","tsptest.armresourceprovider.models.ResourceLroNoBody":"TspTest.ArmResourceProvider.ResourceLroNoBody","tsptest.armresourceprovider.models.TopLevelArmResourceUpdate":"Azure.ResourceManager.Foundations.ResourceUpdateModel","tsptest.armresourceprovider.models.UserAssignedIdentity":"Azure.ResourceManager.CommonTypes.UserAssignedIdentity"},"generatedFiles":["src/main/java/module-info.java","src/main/java/tsptest/armresourceprovider/ArmResourceProviderManager.java","src/main/java/tsptest/armresourceprovider/fluent/ArmClient.java","src/main/java/tsptest/armresourceprovider/fluent/ChildExtensionResourceInterfacesClient.java","src/main/java/tsptest/armresourceprovider/fluent/ChildResourcesInterfacesClient.java","src/main/java/tsptest/armresourceprovider/fluent/CustomTemplateResourceInterfacesClient.java","src/main/java/tsptest/armresourceprovider/fluent/ImmutableResourceModelsClient.java","src/main/java/tsptest/armresourceprovider/fluent/LroNoBodiesClient.java","src/main/java/tsptest/armresourceprovider/fluent/ManagedMaintenanceWindowStatusOperationsClient.java","src/main/java/tsptest/armresourceprovider/fluent/ModelInterfaceSameNamesClient.java","src/main/java/tsptest/armresourceprovider/fluent/OperationsClient.java","src/main/java/tsptest/armresourceprovider/fluent/TopLevelArmResourceInterfacesClient.java","src/main/java/tsptest/armresourceprovider/fluent/models/ChildExtensionResourceInner.java","src/main/java/tsptest/armresourceprovider/fluent/models/ChildResourceInner.java","src/main/java/tsptest/armresourceprovider/fluent/models/ChildResourceProperties.java","src/main/java/tsptest/armresourceprovider/fluent/models/CustomTemplateResourceInner.java","src/main/java/tsptest/armresourceprovider/fluent/models/CustomTemplateResourceProperties.java","src/main/java/tsptest/armresourceprovider/fluent/models/ManagedMaintenanceWindowStatusContentProperties.java","src/main/java/tsptest/armresourceprovider/fluent/models/ManagedMaintenanceWindowStatusInner.java","src/main/java/tsptest/armresourceprovider/fluent/models/ModelInterfaceDifferentNameProperties.java","src/main/java/tsptest/armresourceprovider/fluent/models/ModelInterfaceSameNameInner.java","src/main/java/tsptest/armresourceprovider/fluent/models/OperationInner.java","src/main/java/tsptest/armresourceprovider/fluent/models/ResourceLroNoBodyProperties.java","src/main/java/tsptest/armresourceprovider/fluent/models/ResultInner.java","src/main/java/tsptest/armresourceprovider/fluent/models/TopLevelArmResourceInner.java","src/main/java/tsptest/armresourceprovider/fluent/models/TopLevelArmResourceProperties.java","src/main/java/tsptest/armresourceprovider/fluent/models/TopLevelArmResourceUpdateProperties.java","src/main/java/tsptest/armresourceprovider/fluent/models/package-info.java","src/main/java/tsptest/armresourceprovider/fluent/package-info.java","src/main/java/tsptest/armresourceprovider/implementation/ArmClientBuilder.java","src/main/java/tsptest/armresourceprovider/implementation/ArmClientImpl.java","src/main/java/tsptest/armresourceprovider/implementation/ChildExtensionResourceImpl.java","src/main/java/tsptest/armresourceprovider/implementation/ChildExtensionResourceInterfacesClientImpl.java","src/main/java/tsptest/armresourceprovider/implementation/ChildExtensionResourceInterfacesImpl.java","src/main/java/tsptest/armresourceprovider/implementation/ChildResourceImpl.java","src/main/java/tsptest/armresourceprovider/implementation/ChildResourcesInterfacesClientImpl.java","src/main/java/tsptest/armresourceprovider/implementation/ChildResourcesInterfacesImpl.java","src/main/java/tsptest/armresourceprovider/implementation/CustomTemplateResourceImpl.java","src/main/java/tsptest/armresourceprovider/implementation/CustomTemplateResourceInterfacesClientImpl.java","src/main/java/tsptest/armresourceprovider/implementation/CustomTemplateResourceInterfacesImpl.java","src/main/java/tsptest/armresourceprovider/implementation/ImmutableResourceModelsClientImpl.java","src/main/java/tsptest/armresourceprovider/implementation/ImmutableResourceModelsImpl.java","src/main/java/tsptest/armresourceprovider/implementation/LroNoBodiesClientImpl.java","src/main/java/tsptest/armresourceprovider/implementation/LroNoBodiesImpl.java","src/main/java/tsptest/armresourceprovider/implementation/ManagedMaintenanceWindowStatusImpl.java","src/main/java/tsptest/armresourceprovider/implementation/ManagedMaintenanceWindowStatusOperationsClientImpl.java","src/main/java/tsptest/armresourceprovider/implementation/ManagedMaintenanceWindowStatusOperationsImpl.java","src/main/java/tsptest/armresourceprovider/implementation/ModelInterfaceSameNameImpl.java","src/main/java/tsptest/armresourceprovider/implementation/ModelInterfaceSameNamesClientImpl.java","src/main/java/tsptest/armresourceprovider/implementation/ModelInterfaceSameNamesImpl.java","src/main/java/tsptest/armresourceprovider/implementation/OperationImpl.java","src/main/java/tsptest/armresourceprovider/implementation/OperationsClientImpl.java","src/main/java/tsptest/armresourceprovider/implementation/OperationsImpl.java","src/main/java/tsptest/armresourceprovider/implementation/ResourceManagerUtils.java","src/main/java/tsptest/armresourceprovider/implementation/ResultImpl.java","src/main/java/tsptest/armresourceprovider/implementation/TopLevelArmResourceImpl.java","src/main/java/tsptest/armresourceprovider/implementation/TopLevelArmResourceInterfacesClientImpl.java","src/main/java/tsptest/armresourceprovider/implementation/TopLevelArmResourceInterfacesImpl.java","src/main/java/tsptest/armresourceprovider/implementation/models/ChildExtensionResourceListResult.java","src/main/java/tsptest/armresourceprovider/implementation/models/ChildResourceListResult.java","src/main/java/tsptest/armresourceprovider/implementation/models/OperationListResult.java","src/main/java/tsptest/armresourceprovider/implementation/models/ResourceListResult.java","src/main/java/tsptest/armresourceprovider/implementation/package-info.java","src/main/java/tsptest/armresourceprovider/models/ActionType.java","src/main/java/tsptest/armresourceprovider/models/AnonymousEmptyModel.java","src/main/java/tsptest/armresourceprovider/models/ChildExtensionResource.java","src/main/java/tsptest/armresourceprovider/models/ChildExtensionResourceInterfaces.java","src/main/java/tsptest/armresourceprovider/models/ChildExtensionResourceProperties.java","src/main/java/tsptest/armresourceprovider/models/ChildExtensionResourceUpdate.java","src/main/java/tsptest/armresourceprovider/models/ChildResource.java","src/main/java/tsptest/armresourceprovider/models/ChildResourceUpdate.java","src/main/java/tsptest/armresourceprovider/models/ChildResourcesInterfaces.java","src/main/java/tsptest/armresourceprovider/models/CustomTemplateResource.java","src/main/java/tsptest/armresourceprovider/models/CustomTemplateResourceInterfaces.java","src/main/java/tsptest/armresourceprovider/models/CustomTemplateResourcePatch.java","src/main/java/tsptest/armresourceprovider/models/Dog.java","src/main/java/tsptest/armresourceprovider/models/DogKind.java","src/main/java/tsptest/armresourceprovider/models/EmptyModel.java","src/main/java/tsptest/armresourceprovider/models/Golden.java","src/main/java/tsptest/armresourceprovider/models/ImmutableResourceModels.java","src/main/java/tsptest/armresourceprovider/models/LroNoBodies.java","src/main/java/tsptest/armresourceprovider/models/ManagedMaintenanceWindowStatus.java","src/main/java/tsptest/armresourceprovider/models/ManagedMaintenanceWindowStatusOperations.java","src/main/java/tsptest/armresourceprovider/models/ManagedServiceIdentity.java","src/main/java/tsptest/armresourceprovider/models/ManagedServiceIdentityType.java","src/main/java/tsptest/armresourceprovider/models/ModelInterfaceSameName.java","src/main/java/tsptest/armresourceprovider/models/ModelInterfaceSameNames.java","src/main/java/tsptest/armresourceprovider/models/NginxConfigurationRequest.java","src/main/java/tsptest/armresourceprovider/models/NginxConfigurationResponse.java","src/main/java/tsptest/armresourceprovider/models/NginxConfigurationResponseProperties.java","src/main/java/tsptest/armresourceprovider/models/Operation.java","src/main/java/tsptest/armresourceprovider/models/OperationDisplay.java","src/main/java/tsptest/armresourceprovider/models/Operations.java","src/main/java/tsptest/armresourceprovider/models/Origin.java","src/main/java/tsptest/armresourceprovider/models/PriorityModel.java","src/main/java/tsptest/armresourceprovider/models/ProvisioningState.java","src/main/java/tsptest/armresourceprovider/models/ResourceLroNoBody.java","src/main/java/tsptest/armresourceprovider/models/Result.java","src/main/java/tsptest/armresourceprovider/models/TopLevelArmResource.java","src/main/java/tsptest/armresourceprovider/models/TopLevelArmResourceInterfaces.java","src/main/java/tsptest/armresourceprovider/models/TopLevelArmResourceUpdate.java","src/main/java/tsptest/armresourceprovider/models/UserAssignedIdentity.java","src/main/java/tsptest/armresourceprovider/models/package-info.java","src/main/java/tsptest/armresourceprovider/package-info.java"]} \ No newline at end of file +{"flavor":"Azure","apiVersion":"2023-11-01","crossLanguageDefinitions":{"tsptest.armresourceprovider.fluent.ArmClient":"TspTest.ArmResourceProvider","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient":"TspTest.ArmResourceProvider.ChildExtensionResourceInterface","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.beginCreateOrUpdate":"Azure.ResourceManager.ChildExtensionResourceInterface.createOrUpdate","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.beginCreateOrUpdateAsync":"Azure.ResourceManager.ChildExtensionResourceInterface.createOrUpdate","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.beginDelete":"Azure.ResourceManager.ChildExtensionResourceInterface.delete","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.beginDeleteAsync":"Azure.ResourceManager.ChildExtensionResourceInterface.delete","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.createOrUpdate":"Azure.ResourceManager.ChildExtensionResourceInterface.createOrUpdate","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.createOrUpdateAsync":"Azure.ResourceManager.ChildExtensionResourceInterface.createOrUpdate","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.createOrUpdateWithResponseAsync":"Azure.ResourceManager.ChildExtensionResourceInterface.createOrUpdate","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.delete":"Azure.ResourceManager.ChildExtensionResourceInterface.delete","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.deleteAsync":"Azure.ResourceManager.ChildExtensionResourceInterface.delete","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.deleteWithResponseAsync":"Azure.ResourceManager.ChildExtensionResourceInterface.delete","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.get":"Azure.ResourceManager.ChildExtensionResourceInterface.get","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.getAsync":"Azure.ResourceManager.ChildExtensionResourceInterface.get","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.getWithResponse":"Azure.ResourceManager.ChildExtensionResourceInterface.get","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.getWithResponseAsync":"Azure.ResourceManager.ChildExtensionResourceInterface.get","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.listByTopLevelArmResource":"Azure.ResourceManager.ChildExtensionResourceInterface.listByTopLevelArmResource","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.listByTopLevelArmResourceAsync":"Azure.ResourceManager.ChildExtensionResourceInterface.listByTopLevelArmResource","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.update":"Azure.ResourceManager.ChildExtensionResourceInterface.update","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.updateAsync":"Azure.ResourceManager.ChildExtensionResourceInterface.update","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.updateWithResponse":"Azure.ResourceManager.ChildExtensionResourceInterface.update","tsptest.armresourceprovider.fluent.ChildExtensionResourceInterfacesClient.updateWithResponseAsync":"Azure.ResourceManager.ChildExtensionResourceInterface.update","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient":"TspTest.ArmResourceProvider.ChildResourcesInterface","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.actionWithoutBody":"TspTest.ArmResourceProvider.ChildResourcesInterface.actionWithoutBody","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.actionWithoutBodyAsync":"TspTest.ArmResourceProvider.ChildResourcesInterface.actionWithoutBody","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.actionWithoutBodyWithResponseAsync":"TspTest.ArmResourceProvider.ChildResourcesInterface.actionWithoutBody","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.beginActionWithoutBody":"TspTest.ArmResourceProvider.ChildResourcesInterface.actionWithoutBody","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.beginActionWithoutBodyAsync":"TspTest.ArmResourceProvider.ChildResourcesInterface.actionWithoutBody","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.beginCreateOrUpdate":"Azure.ResourceManager.ChildResourcesInterface.createOrUpdate","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.beginCreateOrUpdateAsync":"Azure.ResourceManager.ChildResourcesInterface.createOrUpdate","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.beginDelete":"Azure.ResourceManager.ChildResourcesInterface.delete","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.beginDeleteAsync":"Azure.ResourceManager.ChildResourcesInterface.delete","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.createOrUpdate":"Azure.ResourceManager.ChildResourcesInterface.createOrUpdate","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.createOrUpdateAsync":"Azure.ResourceManager.ChildResourcesInterface.createOrUpdate","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.createOrUpdateWithResponseAsync":"Azure.ResourceManager.ChildResourcesInterface.createOrUpdate","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.delete":"Azure.ResourceManager.ChildResourcesInterface.delete","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.deleteAsync":"Azure.ResourceManager.ChildResourcesInterface.delete","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.deleteWithResponseAsync":"Azure.ResourceManager.ChildResourcesInterface.delete","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.get":"Azure.ResourceManager.ChildResourcesInterface.get","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.getAsync":"Azure.ResourceManager.ChildResourcesInterface.get","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.getWithResponse":"Azure.ResourceManager.ChildResourcesInterface.get","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.getWithResponseAsync":"Azure.ResourceManager.ChildResourcesInterface.get","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.listByTopLevelArmResource":"TspTest.ArmResourceProvider.ChildResourcesInterface.listByTopLevelArmResource","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.listByTopLevelArmResourceAsync":"TspTest.ArmResourceProvider.ChildResourcesInterface.listByTopLevelArmResource","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.update":"Azure.ResourceManager.ChildResourcesInterface.update","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.updateAsync":"Azure.ResourceManager.ChildResourcesInterface.update","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.updateWithResponse":"Azure.ResourceManager.ChildResourcesInterface.update","tsptest.armresourceprovider.fluent.ChildResourcesInterfacesClient.updateWithResponseAsync":"Azure.ResourceManager.ChildResourcesInterface.update","tsptest.armresourceprovider.fluent.CustomTemplateResourceInterfacesClient":"TspTest.ArmResourceProvider.CustomTemplateResourceInterface","tsptest.armresourceprovider.fluent.CustomTemplateResourceInterfacesClient.beginCreateOrUpdate":"Azure.ResourceManager.CustomTemplateResourceInterface.createOrUpdate","tsptest.armresourceprovider.fluent.CustomTemplateResourceInterfacesClient.beginCreateOrUpdateAsync":"Azure.ResourceManager.CustomTemplateResourceInterface.createOrUpdate","tsptest.armresourceprovider.fluent.CustomTemplateResourceInterfacesClient.beginUpdateLongRunning":"TspTest.ArmResourceProvider.CustomTemplateResourceInterface.updateLongRunning","tsptest.armresourceprovider.fluent.CustomTemplateResourceInterfacesClient.beginUpdateLongRunningAsync":"TspTest.ArmResourceProvider.CustomTemplateResourceInterface.updateLongRunning","tsptest.armresourceprovider.fluent.CustomTemplateResourceInterfacesClient.createOrUpdate":"Azure.ResourceManager.CustomTemplateResourceInterface.createOrUpdate","tsptest.armresourceprovider.fluent.CustomTemplateResourceInterfacesClient.createOrUpdateAsync":"Azure.ResourceManager.CustomTemplateResourceInterface.createOrUpdate","tsptest.armresourceprovider.fluent.CustomTemplateResourceInterfacesClient.createOrUpdateWithResponseAsync":"Azure.ResourceManager.CustomTemplateResourceInterface.createOrUpdate","tsptest.armresourceprovider.fluent.CustomTemplateResourceInterfacesClient.updateLongRunning":"TspTest.ArmResourceProvider.CustomTemplateResourceInterface.updateLongRunning","tsptest.armresourceprovider.fluent.CustomTemplateResourceInterfacesClient.updateLongRunningAsync":"TspTest.ArmResourceProvider.CustomTemplateResourceInterface.updateLongRunning","tsptest.armresourceprovider.fluent.CustomTemplateResourceInterfacesClient.updateLongRunningWithResponseAsync":"TspTest.ArmResourceProvider.CustomTemplateResourceInterface.updateLongRunning","tsptest.armresourceprovider.fluent.ImmutableResourceModelsClient":"TspTest.ArmResourceProvider.ImmutableResourceModel","tsptest.armresourceprovider.fluent.ImmutableResourceModelsClient.beginCreateOrUpdate":"TspTest.ArmResourceProvider.ImmutableResourceModel.createOrUpdate","tsptest.armresourceprovider.fluent.ImmutableResourceModelsClient.beginCreateOrUpdateAsync":"TspTest.ArmResourceProvider.ImmutableResourceModel.createOrUpdate","tsptest.armresourceprovider.fluent.ImmutableResourceModelsClient.createOrUpdate":"TspTest.ArmResourceProvider.ImmutableResourceModel.createOrUpdate","tsptest.armresourceprovider.fluent.ImmutableResourceModelsClient.createOrUpdateAsync":"TspTest.ArmResourceProvider.ImmutableResourceModel.createOrUpdate","tsptest.armresourceprovider.fluent.ImmutableResourceModelsClient.createOrUpdateWithResponseAsync":"TspTest.ArmResourceProvider.ImmutableResourceModel.createOrUpdate","tsptest.armresourceprovider.fluent.LroNoBodiesClient":"TspTest.ArmResourceProvider.LroNoBody","tsptest.armresourceprovider.fluent.LroNoBodiesClient.action":"TspTest.ArmResourceProvider.LroNoBody.action","tsptest.armresourceprovider.fluent.LroNoBodiesClient.actionAsync":"TspTest.ArmResourceProvider.LroNoBody.action","tsptest.armresourceprovider.fluent.LroNoBodiesClient.actionWithResponseAsync":"TspTest.ArmResourceProvider.LroNoBody.action","tsptest.armresourceprovider.fluent.LroNoBodiesClient.beginAction":"TspTest.ArmResourceProvider.LroNoBody.action","tsptest.armresourceprovider.fluent.LroNoBodiesClient.beginActionAsync":"TspTest.ArmResourceProvider.LroNoBody.action","tsptest.armresourceprovider.fluent.LroNoBodiesClient.beginCreateOrUpdate":"TspTest.ArmResourceProvider.LroNoBody.createOrUpdate","tsptest.armresourceprovider.fluent.LroNoBodiesClient.beginCreateOrUpdateAsync":"TspTest.ArmResourceProvider.LroNoBody.createOrUpdate","tsptest.armresourceprovider.fluent.LroNoBodiesClient.createOrUpdate":"TspTest.ArmResourceProvider.LroNoBody.createOrUpdate","tsptest.armresourceprovider.fluent.LroNoBodiesClient.createOrUpdateAsync":"TspTest.ArmResourceProvider.LroNoBody.createOrUpdate","tsptest.armresourceprovider.fluent.LroNoBodiesClient.createOrUpdateWithResponseAsync":"TspTest.ArmResourceProvider.LroNoBody.createOrUpdate","tsptest.armresourceprovider.fluent.ManagedMaintenanceWindowStatusOperationsClient":"TspTest.ArmResourceProvider.ManagedMaintenanceWindowStatus","tsptest.armresourceprovider.fluent.ManagedMaintenanceWindowStatusOperationsClient.beginDelete":"TspTest.ArmResourceProvider.ManagedMaintenanceWindowStatus.delete","tsptest.armresourceprovider.fluent.ManagedMaintenanceWindowStatusOperationsClient.beginDeleteAsync":"TspTest.ArmResourceProvider.ManagedMaintenanceWindowStatus.delete","tsptest.armresourceprovider.fluent.ManagedMaintenanceWindowStatusOperationsClient.delete":"TspTest.ArmResourceProvider.ManagedMaintenanceWindowStatus.delete","tsptest.armresourceprovider.fluent.ManagedMaintenanceWindowStatusOperationsClient.deleteAsync":"TspTest.ArmResourceProvider.ManagedMaintenanceWindowStatus.delete","tsptest.armresourceprovider.fluent.ManagedMaintenanceWindowStatusOperationsClient.deleteWithResponseAsync":"TspTest.ArmResourceProvider.ManagedMaintenanceWindowStatus.delete","tsptest.armresourceprovider.fluent.ManagedMaintenanceWindowStatusOperationsClient.getByResourceGroup":"TspTest.ArmResourceProvider.ManagedMaintenanceWindowStatus.get","tsptest.armresourceprovider.fluent.ManagedMaintenanceWindowStatusOperationsClient.getByResourceGroupAsync":"TspTest.ArmResourceProvider.ManagedMaintenanceWindowStatus.get","tsptest.armresourceprovider.fluent.ManagedMaintenanceWindowStatusOperationsClient.getByResourceGroupWithResponse":"TspTest.ArmResourceProvider.ManagedMaintenanceWindowStatus.get","tsptest.armresourceprovider.fluent.ManagedMaintenanceWindowStatusOperationsClient.getByResourceGroupWithResponseAsync":"TspTest.ArmResourceProvider.ManagedMaintenanceWindowStatus.get","tsptest.armresourceprovider.fluent.ModelInterfaceSameNamesClient":"TspTest.ArmResourceProvider.ModelInterfaceSameName","tsptest.armresourceprovider.fluent.ModelInterfaceSameNamesClient.delete":"TspTest.ArmResourceProvider.ModelInterfaceSameName.delete","tsptest.armresourceprovider.fluent.ModelInterfaceSameNamesClient.deleteAsync":"TspTest.ArmResourceProvider.ModelInterfaceSameName.delete","tsptest.armresourceprovider.fluent.ModelInterfaceSameNamesClient.deleteWithResponse":"TspTest.ArmResourceProvider.ModelInterfaceSameName.delete","tsptest.armresourceprovider.fluent.ModelInterfaceSameNamesClient.deleteWithResponseAsync":"TspTest.ArmResourceProvider.ModelInterfaceSameName.delete","tsptest.armresourceprovider.fluent.ModelInterfaceSameNamesClient.getByResourceGroup":"TspTest.ArmResourceProvider.ModelInterfaceSameName.get","tsptest.armresourceprovider.fluent.ModelInterfaceSameNamesClient.getByResourceGroupAsync":"TspTest.ArmResourceProvider.ModelInterfaceSameName.get","tsptest.armresourceprovider.fluent.ModelInterfaceSameNamesClient.getByResourceGroupWithResponse":"TspTest.ArmResourceProvider.ModelInterfaceSameName.get","tsptest.armresourceprovider.fluent.ModelInterfaceSameNamesClient.getByResourceGroupWithResponseAsync":"TspTest.ArmResourceProvider.ModelInterfaceSameName.get","tsptest.armresourceprovider.fluent.OperationsClient":"TspTest.ArmResourceProvider.Operations","tsptest.armresourceprovider.fluent.OperationsClient.list":"Azure.ResourceManager.Operations.list","tsptest.armresourceprovider.fluent.OperationsClient.listAsync":"Azure.ResourceManager.Operations.list","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient":"TspTest.ArmResourceProvider.TopLevelArmResourceInterface","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.action":"TspTest.ArmResourceProvider.TopLevelArmResourceInterface.action","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.actionAsync":"TspTest.ArmResourceProvider.TopLevelArmResourceInterface.action","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.actionWithResponseAsync":"TspTest.ArmResourceProvider.TopLevelArmResourceInterface.action","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.beginAction":"TspTest.ArmResourceProvider.TopLevelArmResourceInterface.action","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.beginActionAsync":"TspTest.ArmResourceProvider.TopLevelArmResourceInterface.action","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.beginCreateOrUpdate":"Azure.ResourceManager.TopLevelArmResourceInterface.createOrUpdate","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.beginCreateOrUpdateAsync":"Azure.ResourceManager.TopLevelArmResourceInterface.createOrUpdate","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.beginDelete":"Azure.ResourceManager.TopLevelArmResourceInterface.delete","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.beginDeleteAsync":"Azure.ResourceManager.TopLevelArmResourceInterface.delete","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.createOrUpdate":"Azure.ResourceManager.TopLevelArmResourceInterface.createOrUpdate","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.createOrUpdateAsync":"Azure.ResourceManager.TopLevelArmResourceInterface.createOrUpdate","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.createOrUpdateWithResponseAsync":"Azure.ResourceManager.TopLevelArmResourceInterface.createOrUpdate","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.delete":"Azure.ResourceManager.TopLevelArmResourceInterface.delete","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.deleteAsync":"Azure.ResourceManager.TopLevelArmResourceInterface.delete","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.deleteWithResponseAsync":"Azure.ResourceManager.TopLevelArmResourceInterface.delete","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.getByResourceGroup":"Azure.ResourceManager.TopLevelArmResourceInterface.get","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.getByResourceGroupAsync":"Azure.ResourceManager.TopLevelArmResourceInterface.get","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.getByResourceGroupWithResponse":"Azure.ResourceManager.TopLevelArmResourceInterface.get","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.getByResourceGroupWithResponseAsync":"Azure.ResourceManager.TopLevelArmResourceInterface.get","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.list":"Azure.ResourceManager.TopLevelArmResourceInterface.listBySubscription","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.listAsync":"Azure.ResourceManager.TopLevelArmResourceInterface.listBySubscription","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.listByResourceGroup":"Azure.ResourceManager.TopLevelArmResourceInterface.listByResourceGroup","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.listByResourceGroupAsync":"Azure.ResourceManager.TopLevelArmResourceInterface.listByResourceGroup","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.update":"Azure.ResourceManager.TopLevelArmResourceInterface.update","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.updateAsync":"Azure.ResourceManager.TopLevelArmResourceInterface.update","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.updateWithResponse":"Azure.ResourceManager.TopLevelArmResourceInterface.update","tsptest.armresourceprovider.fluent.TopLevelArmResourceInterfacesClient.updateWithResponseAsync":"Azure.ResourceManager.TopLevelArmResourceInterface.update","tsptest.armresourceprovider.fluent.models.ChildExtensionResourceInner":"TspTest.ArmResourceProvider.ChildExtensionResource","tsptest.armresourceprovider.fluent.models.ChildResourceInner":"TspTest.ArmResourceProvider.ChildResource","tsptest.armresourceprovider.fluent.models.ChildResourceProperties":"TspTest.ArmResourceProvider.ChildResourceProperties","tsptest.armresourceprovider.fluent.models.CustomTemplateResourceInner":"TspTest.ArmResourceProvider.CustomTemplateResource","tsptest.armresourceprovider.fluent.models.CustomTemplateResourceProperties":"TspTest.ArmResourceProvider.CustomTemplateResourceProperties","tsptest.armresourceprovider.fluent.models.ManagedMaintenanceWindowStatusContentProperties":"TspTest.ArmResourceProvider.ManagedMaintenanceWindowStatusContentProperties","tsptest.armresourceprovider.fluent.models.ManagedMaintenanceWindowStatusInner":"TspTest.ArmResourceProvider.ManagedMaintenanceWindowStatusContent","tsptest.armresourceprovider.fluent.models.ModelInterfaceDifferentNameProperties":"TspTest.ArmResourceProvider.ModelInterfaceDifferentNameProperties","tsptest.armresourceprovider.fluent.models.ModelInterfaceSameNameInner":"TspTest.ArmResourceProvider.ModelInterfaceDifferentName","tsptest.armresourceprovider.fluent.models.OperationInner":"Azure.ResourceManager.CommonTypes.Operation","tsptest.armresourceprovider.fluent.models.ResourceLroNoBodyProperties":"TspTest.ArmResourceProvider.ResourceLroNoBodyProperties","tsptest.armresourceprovider.fluent.models.ResultInner":"TspTest.ArmResourceProvider.Result","tsptest.armresourceprovider.fluent.models.TopLevelArmResourceInner":"TspTest.ArmResourceProvider.TopLevelArmResource","tsptest.armresourceprovider.fluent.models.TopLevelArmResourceProperties":"TspTest.ArmResourceProvider.TopLevelArmResourceProperties","tsptest.armresourceprovider.fluent.models.TopLevelArmResourceUpdateProperties":"Azure.ResourceManager.Foundations.ResourceUpdateModelProperties","tsptest.armresourceprovider.implementation.ArmClientBuilder":"TspTest.ArmResourceProvider","tsptest.armresourceprovider.implementation.models.ChildExtensionResourceListResult":"Azure.ResourceManager.ResourceListResult","tsptest.armresourceprovider.implementation.models.ChildResourceListResult":"TspTest.ArmResourceProvider.ChildResourceListResult","tsptest.armresourceprovider.implementation.models.OperationListResult":"Azure.ResourceManager.CommonTypes.OperationListResult","tsptest.armresourceprovider.implementation.models.ResourceListResult":"Azure.ResourceManager.ResourceListResult","tsptest.armresourceprovider.models.ActionFinalResult":"TspTest.ArmResourceProvider.ActionFinalResult","tsptest.armresourceprovider.models.ActionType":"Azure.ResourceManager.CommonTypes.ActionType","tsptest.armresourceprovider.models.AnonymousEmptyModel":"TspTest.ArmResourceProvider.CustomTemplateResourceProperties.anonymousEmptyModel.anonymous","tsptest.armresourceprovider.models.ChildExtensionResourceProperties":"TspTest.ArmResourceProvider.ChildExtensionResourceProperties","tsptest.armresourceprovider.models.ChildExtensionResourceUpdate":"Azure.ResourceManager.Foundations.ResourceUpdateModel","tsptest.armresourceprovider.models.ChildResourceUpdate":"Azure.ResourceManager.Foundations.ResourceUpdateModel","tsptest.armresourceprovider.models.CustomTemplateResourcePatch":"TspTest.ArmResourceProvider.CustomTemplateResourcePatch","tsptest.armresourceprovider.models.Dog":"TspTest.ArmResourceProvider.Dog","tsptest.armresourceprovider.models.DogKind":"TspTest.ArmResourceProvider.DogKind","tsptest.armresourceprovider.models.EmptyModel":"TspTest.ArmResourceProvider.EmptyModel","tsptest.armresourceprovider.models.Golden":"TspTest.ArmResourceProvider.Golden","tsptest.armresourceprovider.models.ManagedServiceIdentity":"Azure.ResourceManager.CommonTypes.ManagedServiceIdentity","tsptest.armresourceprovider.models.ManagedServiceIdentityType":"Azure.ResourceManager.CommonTypes.ManagedServiceIdentityType","tsptest.armresourceprovider.models.NginxConfigurationRequest":"TspTest.ArmResourceProvider.NginxConfigurationRequest","tsptest.armresourceprovider.models.NginxConfigurationResponse":"TspTest.ArmResourceProvider.NginxConfigurationResponse","tsptest.armresourceprovider.models.NginxConfigurationResponseProperties":"TspTest.ArmResourceProvider.NginxConfigurationResponseProperties","tsptest.armresourceprovider.models.OperationDisplay":"Azure.ResourceManager.CommonTypes.OperationDisplay","tsptest.armresourceprovider.models.Origin":"Azure.ResourceManager.CommonTypes.Origin","tsptest.armresourceprovider.models.PriorityModel":"TspTest.ArmResourceProvider.PriorityModel","tsptest.armresourceprovider.models.ProvisioningState":"TspTest.ArmResourceProvider.ProvisioningState","tsptest.armresourceprovider.models.ResourceLroNoBody":"TspTest.ArmResourceProvider.ResourceLroNoBody","tsptest.armresourceprovider.models.TopLevelArmResourceUpdate":"Azure.ResourceManager.Foundations.ResourceUpdateModel","tsptest.armresourceprovider.models.UserAssignedIdentity":"Azure.ResourceManager.CommonTypes.UserAssignedIdentity"},"generatedFiles":["src/main/java/module-info.java","src/main/java/tsptest/armresourceprovider/ArmResourceProviderManager.java","src/main/java/tsptest/armresourceprovider/fluent/ArmClient.java","src/main/java/tsptest/armresourceprovider/fluent/ChildExtensionResourceInterfacesClient.java","src/main/java/tsptest/armresourceprovider/fluent/ChildResourcesInterfacesClient.java","src/main/java/tsptest/armresourceprovider/fluent/CustomTemplateResourceInterfacesClient.java","src/main/java/tsptest/armresourceprovider/fluent/ImmutableResourceModelsClient.java","src/main/java/tsptest/armresourceprovider/fluent/LroNoBodiesClient.java","src/main/java/tsptest/armresourceprovider/fluent/ManagedMaintenanceWindowStatusOperationsClient.java","src/main/java/tsptest/armresourceprovider/fluent/ModelInterfaceSameNamesClient.java","src/main/java/tsptest/armresourceprovider/fluent/OperationsClient.java","src/main/java/tsptest/armresourceprovider/fluent/TopLevelArmResourceInterfacesClient.java","src/main/java/tsptest/armresourceprovider/fluent/models/ChildExtensionResourceInner.java","src/main/java/tsptest/armresourceprovider/fluent/models/ChildResourceInner.java","src/main/java/tsptest/armresourceprovider/fluent/models/ChildResourceProperties.java","src/main/java/tsptest/armresourceprovider/fluent/models/CustomTemplateResourceInner.java","src/main/java/tsptest/armresourceprovider/fluent/models/CustomTemplateResourceProperties.java","src/main/java/tsptest/armresourceprovider/fluent/models/ManagedMaintenanceWindowStatusContentProperties.java","src/main/java/tsptest/armresourceprovider/fluent/models/ManagedMaintenanceWindowStatusInner.java","src/main/java/tsptest/armresourceprovider/fluent/models/ModelInterfaceDifferentNameProperties.java","src/main/java/tsptest/armresourceprovider/fluent/models/ModelInterfaceSameNameInner.java","src/main/java/tsptest/armresourceprovider/fluent/models/OperationInner.java","src/main/java/tsptest/armresourceprovider/fluent/models/ResourceLroNoBodyProperties.java","src/main/java/tsptest/armresourceprovider/fluent/models/ResultInner.java","src/main/java/tsptest/armresourceprovider/fluent/models/TopLevelArmResourceInner.java","src/main/java/tsptest/armresourceprovider/fluent/models/TopLevelArmResourceProperties.java","src/main/java/tsptest/armresourceprovider/fluent/models/TopLevelArmResourceUpdateProperties.java","src/main/java/tsptest/armresourceprovider/fluent/models/package-info.java","src/main/java/tsptest/armresourceprovider/fluent/package-info.java","src/main/java/tsptest/armresourceprovider/implementation/ArmClientBuilder.java","src/main/java/tsptest/armresourceprovider/implementation/ArmClientImpl.java","src/main/java/tsptest/armresourceprovider/implementation/ChildExtensionResourceImpl.java","src/main/java/tsptest/armresourceprovider/implementation/ChildExtensionResourceInterfacesClientImpl.java","src/main/java/tsptest/armresourceprovider/implementation/ChildExtensionResourceInterfacesImpl.java","src/main/java/tsptest/armresourceprovider/implementation/ChildResourceImpl.java","src/main/java/tsptest/armresourceprovider/implementation/ChildResourcesInterfacesClientImpl.java","src/main/java/tsptest/armresourceprovider/implementation/ChildResourcesInterfacesImpl.java","src/main/java/tsptest/armresourceprovider/implementation/CustomTemplateResourceImpl.java","src/main/java/tsptest/armresourceprovider/implementation/CustomTemplateResourceInterfacesClientImpl.java","src/main/java/tsptest/armresourceprovider/implementation/CustomTemplateResourceInterfacesImpl.java","src/main/java/tsptest/armresourceprovider/implementation/ImmutableResourceModelsClientImpl.java","src/main/java/tsptest/armresourceprovider/implementation/ImmutableResourceModelsImpl.java","src/main/java/tsptest/armresourceprovider/implementation/LroNoBodiesClientImpl.java","src/main/java/tsptest/armresourceprovider/implementation/LroNoBodiesImpl.java","src/main/java/tsptest/armresourceprovider/implementation/ManagedMaintenanceWindowStatusImpl.java","src/main/java/tsptest/armresourceprovider/implementation/ManagedMaintenanceWindowStatusOperationsClientImpl.java","src/main/java/tsptest/armresourceprovider/implementation/ManagedMaintenanceWindowStatusOperationsImpl.java","src/main/java/tsptest/armresourceprovider/implementation/ModelInterfaceSameNameImpl.java","src/main/java/tsptest/armresourceprovider/implementation/ModelInterfaceSameNamesClientImpl.java","src/main/java/tsptest/armresourceprovider/implementation/ModelInterfaceSameNamesImpl.java","src/main/java/tsptest/armresourceprovider/implementation/OperationImpl.java","src/main/java/tsptest/armresourceprovider/implementation/OperationsClientImpl.java","src/main/java/tsptest/armresourceprovider/implementation/OperationsImpl.java","src/main/java/tsptest/armresourceprovider/implementation/ResourceManagerUtils.java","src/main/java/tsptest/armresourceprovider/implementation/ResultImpl.java","src/main/java/tsptest/armresourceprovider/implementation/TopLevelArmResourceImpl.java","src/main/java/tsptest/armresourceprovider/implementation/TopLevelArmResourceInterfacesClientImpl.java","src/main/java/tsptest/armresourceprovider/implementation/TopLevelArmResourceInterfacesImpl.java","src/main/java/tsptest/armresourceprovider/implementation/models/ChildExtensionResourceListResult.java","src/main/java/tsptest/armresourceprovider/implementation/models/ChildResourceListResult.java","src/main/java/tsptest/armresourceprovider/implementation/models/OperationListResult.java","src/main/java/tsptest/armresourceprovider/implementation/models/ResourceListResult.java","src/main/java/tsptest/armresourceprovider/implementation/package-info.java","src/main/java/tsptest/armresourceprovider/models/ActionFinalResult.java","src/main/java/tsptest/armresourceprovider/models/ActionType.java","src/main/java/tsptest/armresourceprovider/models/AnonymousEmptyModel.java","src/main/java/tsptest/armresourceprovider/models/ChildExtensionResource.java","src/main/java/tsptest/armresourceprovider/models/ChildExtensionResourceInterfaces.java","src/main/java/tsptest/armresourceprovider/models/ChildExtensionResourceProperties.java","src/main/java/tsptest/armresourceprovider/models/ChildExtensionResourceUpdate.java","src/main/java/tsptest/armresourceprovider/models/ChildResource.java","src/main/java/tsptest/armresourceprovider/models/ChildResourceUpdate.java","src/main/java/tsptest/armresourceprovider/models/ChildResourcesInterfaces.java","src/main/java/tsptest/armresourceprovider/models/CustomTemplateResource.java","src/main/java/tsptest/armresourceprovider/models/CustomTemplateResourceInterfaces.java","src/main/java/tsptest/armresourceprovider/models/CustomTemplateResourcePatch.java","src/main/java/tsptest/armresourceprovider/models/Dog.java","src/main/java/tsptest/armresourceprovider/models/DogKind.java","src/main/java/tsptest/armresourceprovider/models/EmptyModel.java","src/main/java/tsptest/armresourceprovider/models/Golden.java","src/main/java/tsptest/armresourceprovider/models/ImmutableResourceModels.java","src/main/java/tsptest/armresourceprovider/models/LroNoBodies.java","src/main/java/tsptest/armresourceprovider/models/ManagedMaintenanceWindowStatus.java","src/main/java/tsptest/armresourceprovider/models/ManagedMaintenanceWindowStatusOperations.java","src/main/java/tsptest/armresourceprovider/models/ManagedServiceIdentity.java","src/main/java/tsptest/armresourceprovider/models/ManagedServiceIdentityType.java","src/main/java/tsptest/armresourceprovider/models/ModelInterfaceSameName.java","src/main/java/tsptest/armresourceprovider/models/ModelInterfaceSameNames.java","src/main/java/tsptest/armresourceprovider/models/NginxConfigurationRequest.java","src/main/java/tsptest/armresourceprovider/models/NginxConfigurationResponse.java","src/main/java/tsptest/armresourceprovider/models/NginxConfigurationResponseProperties.java","src/main/java/tsptest/armresourceprovider/models/Operation.java","src/main/java/tsptest/armresourceprovider/models/OperationDisplay.java","src/main/java/tsptest/armresourceprovider/models/Operations.java","src/main/java/tsptest/armresourceprovider/models/Origin.java","src/main/java/tsptest/armresourceprovider/models/PriorityModel.java","src/main/java/tsptest/armresourceprovider/models/ProvisioningState.java","src/main/java/tsptest/armresourceprovider/models/ResourceLroNoBody.java","src/main/java/tsptest/armresourceprovider/models/Result.java","src/main/java/tsptest/armresourceprovider/models/TopLevelArmResource.java","src/main/java/tsptest/armresourceprovider/models/TopLevelArmResourceInterfaces.java","src/main/java/tsptest/armresourceprovider/models/TopLevelArmResourceUpdate.java","src/main/java/tsptest/armresourceprovider/models/UserAssignedIdentity.java","src/main/java/tsptest/armresourceprovider/models/package-info.java","src/main/java/tsptest/armresourceprovider/package-info.java"]} \ No newline at end of file diff --git a/packages/http-client-java/generator/http-client-generator-test/src/test/java/tsptest/arm/LroResponseTests.java b/packages/http-client-java/generator/http-client-generator-test/src/test/java/tsptest/arm/LroResponseTests.java new file mode 100644 index 00000000000..a8f9f19908d --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/test/java/tsptest/arm/LroResponseTests.java @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package tsptest.arm; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import tsptest.armresourceprovider.ArmResourceProviderManager; +import tsptest.armresourceprovider.models.ActionFinalResult; + +public class LroResponseTests { + + // compile pass + public void testLroActionFinalResponse() { + ArmResourceProviderManager manager = Mockito.mock(ArmResourceProviderManager.class); + ActionFinalResult actionFinalResult = manager.lroNoBodies().action("resourceGroup", "name"); + } + + @Test + public void testLroActionInitiateResponseNotGenerated() throws ClassNotFoundException { + // ActionFinalResult generated + this.getClass().getClassLoader().loadClass("tsptest.armresourceprovider.models.ActionFinalResult"); + // ActionInitiateResult not generated + Assertions.assertThrows(ClassNotFoundException.class, () -> { + this.getClass().getClassLoader().loadClass("tsptest.armresourceprovider.models.ActionInitiateResult"); + }); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-test/src/test/java/tsptest/armstreamstyleserialization/StreamStyleSerializationTests.java b/packages/http-client-java/generator/http-client-generator-test/src/test/java/tsptest/armstreamstyleserialization/StreamStyleSerializationTests.java index a61869ea74f..e60cde20dd7 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/test/java/tsptest/armstreamstyleserialization/StreamStyleSerializationTests.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/test/java/tsptest/armstreamstyleserialization/StreamStyleSerializationTests.java @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + package tsptest.armstreamstyleserialization; import com.azure.core.http.HttpClient; diff --git a/packages/http-client-java/generator/http-client-generator-test/tsp/arm.tsp b/packages/http-client-java/generator/http-client-generator-test/tsp/arm.tsp index a89ad2ff665..ba694915108 100644 --- a/packages/http-client-java/generator/http-client-generator-test/tsp/arm.tsp +++ b/packages/http-client-java/generator/http-client-generator-test/tsp/arm.tsp @@ -272,6 +272,16 @@ model ResourceLroNoBodyProperties { provisioningState?: ProvisioningState; } +// this model should not be generated +model ActionInitiateResult { + status: string; +} + +// this model should be generated +model ActionFinalResult { + result: string; +} + //----------------------- Paths ----------------------- @armResourceOperations interface ChildResourcesInterface @@ -390,6 +400,15 @@ interface LroNoBody { Response = ArmAcceptedLroResponse & Azure.Core.Foundations.RetryAfterHeader> >; + + @post + action is ArmResourceActionAsync< + ResourceLroNoBody, + void, + ActionInitiateResult, + LroHeaders = ArmCombinedLroHeaders & + Azure.Core.Foundations.RetryAfterHeader + >; } // client configure diff --git a/packages/http-client-java/package-lock.json b/packages/http-client-java/package-lock.json index a4bbdc667de..8274f740ed9 100644 --- a/packages/http-client-java/package-lock.json +++ b/packages/http-client-java/package-lock.json @@ -4989,13 +4989,13 @@ } }, "node_modules/jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.3.tgz", + "integrity": "sha512-byiJ0FLRdLdSVSReO/U4E7RoEyOCKnEnEPMjq3HxWtvzLsV08/i5RQKsFVNkCldrCaPr2vDNAOMsfs8T/Hze7g==", "dev": true, "license": "MIT", "dependencies": { - "jwa": "^1.4.1", + "jwa": "^1.4.2", "safe-buffer": "^5.0.1" } }, From 27036b81ee9f5c92a4ce10ce1508aaa81e4b0aa6 Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Mon, 8 Dec 2025 15:16:38 +0800 Subject: [PATCH 11/40] [Python] Fix multipart when files part is optional (#9144) fix https://github.com/microsoft/typespec/issues/9136 Related PR: - [ ] https://github.com/microsoft/typespec/pull/9139 --- ...ultipart-fix-optional-files-part-2025-11-5-8-29-45.md | 7 +++++++ .../pygen/codegen/serializers/builder_serializer.py | 3 +-- .../generator/pygen/codegen/templates/utils.py.jinja2 | 9 +++++---- 3 files changed, 13 insertions(+), 6 deletions(-) create mode 100644 .chronus/changes/python-multipart-fix-optional-files-part-2025-11-5-8-29-45.md diff --git a/.chronus/changes/python-multipart-fix-optional-files-part-2025-11-5-8-29-45.md b/.chronus/changes/python-multipart-fix-optional-files-part-2025-11-5-8-29-45.md new file mode 100644 index 00000000000..5e44a7a1459 --- /dev/null +++ b/.chronus/changes/python-multipart-fix-optional-files-part-2025-11-5-8-29-45.md @@ -0,0 +1,7 @@ +--- +changeKind: fix +packages: + - "@typespec/http-client-python" +--- + +Fix multipart when files part is optional \ No newline at end of file diff --git a/packages/http-client-python/generator/pygen/codegen/serializers/builder_serializer.py b/packages/http-client-python/generator/pygen/codegen/serializers/builder_serializer.py index cf09a7b95c6..ef61ff347cc 100644 --- a/packages/http-client-python/generator/pygen/codegen/serializers/builder_serializer.py +++ b/packages/http-client-python/generator/pygen/codegen/serializers/builder_serializer.py @@ -679,7 +679,7 @@ def _serialize_body_parameter(self, builder: OperationType) -> list[str]: ")", f"_file_fields: list[str] = {file_fields}", f"_data_fields: list[str] = {data_fields}", - "_files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields)", + "_files = prepare_multipart_form_data(_body, _file_fields, _data_fields)", ] ) return retval @@ -861,7 +861,6 @@ def _create_request_builder_call( retval.append(f" {client_name}=_{client_name},") elif request_builder.has_form_data_body: retval.append(" files=_files,") - retval.append(" data=_data,") elif request_builder.overloads: seen_body_params = set() for overload in request_builder.overloads: diff --git a/packages/http-client-python/generator/pygen/codegen/templates/utils.py.jinja2 b/packages/http-client-python/generator/pygen/codegen/templates/utils.py.jinja2 index f62c6d3bbb0..140f80638cd 100644 --- a/packages/http-client-python/generator/pygen/codegen/templates/utils.py.jinja2 +++ b/packages/http-client-python/generator/pygen/codegen/templates/utils.py.jinja2 @@ -78,9 +78,8 @@ def serialize_multipart_data_entry(data_entry: Any) -> Any: def prepare_multipart_form_data( body: Mapping[str, Any], multipart_fields: list[str], data_fields: list[str] -) -> tuple[list[FileType], dict[str, Any]]: +) -> list[FileType]: files: list[FileType] = [] - data: dict[str, Any] = {} for multipart_field in multipart_fields: multipart_entry = body.get(multipart_field) if isinstance(multipart_entry, list): @@ -88,10 +87,12 @@ def prepare_multipart_form_data( elif multipart_entry: files.append((multipart_field, multipart_entry)) + # if files is empty, sdk core library can't handle multipart/form-data correctly, so + # we put data fields into files with filename as None to avoid that scenario. for data_field in data_fields: data_entry = body.get(data_field) if data_entry: - data[data_field] = serialize_multipart_data_entry(data_entry) + files.append((data_field, str(serialize_multipart_data_entry(data_entry)))) - return files, data + return files {% endif %} From adf2cd5688bd25d9eef2efe8f65b0b8327080bf5 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Mon, 8 Dec 2025 06:20:39 -0800 Subject: [PATCH 12/40] fix: import OpenAPI 3.1/3.2 contentEncoding base64 as bytes with @encode decorator (#9151) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - [x] Analyze the issue: OpenAPI 3.1/3.2 schemas with `contentEncoding: base64` should be imported as `bytes` type with `@encode("base64", string)` decorator - [x] Understand the codebase: The import/convert functionality is in `packages/openapi3/src/cli/actions/convert/` - [x] Modify `generate-types.ts` (`getStringType` function) to handle `contentEncoding: base64` and return `bytes` type - [x] Modify `decorators.ts` (`getStringSchemaDecorators` function) to add `@encode("base64", string)` decorator when `contentEncoding: base64` - [x] Add tests to verify the fix - [x] Run format and lint commands - [x] Add changelog entry - [x] Run code review and address feedback - [x] Manually verify the generated TypeSpec output is correct - [x] Fix TypeScript build error in data-types.test.ts ## Summary This PR fixes the import of OpenAPI 3.1/3.2 schemas with `contentEncoding: base64`. **Before this fix:** ```yaml # OpenAPI 3.1/3.2 properties: b64_json: type: string contentEncoding: base64 ``` Was incorrectly imported as: ```typespec model Foo { b64_json?: string; // Wrong! } ``` **After this fix:** ```typespec model Foo { @encode("base64", string) b64_json?: bytes; // Correct! } ``` ## Security Summary The changes are minimal and focused on type detection during import. No security vulnerabilities were introduced.
Original prompt > > ---- > > *This section details on the original issue you should resolve* > > import - base64 content encoding should be imported as bytes > ### Clear and concise description of the problem > > The following TypeSpec definition > > ```typespec > model Foo { > @encode("base64", string) > b64_json?: bytes; > } > ``` > > Leads to the follow OpenAPI 3.1/3.2 descriptions > > ```yaml > openapi: 3.2.0 > info: > title: (title) > version: 0.0.0 > tags: [] > paths: {} > components: > schemas: > Foo: > type: object > properties: > b64_json: > type: string > contentEncoding: base64 > ``` > > And the following OpenAPI 3.0 description > > ```yaml > openapi: 3.0.0 > info: > title: (title) > version: 0.0.0 > tags: [] > paths: {} > components: > schemas: > Foo: > type: object > properties: > b64_json: > type: string > format: base64 > ``` > > > But importing those to TypeSpec leads to the following result in 3.1/3.2 > > ```typespec > model Foo { > b64_json?: string; > } > ``` > > And this result in 3.0 > > ```typespec > model Foo { > @format("base64") b64_json?: string; > } > ``` > > The import result looks correct for OpenAPI 3.0 due to the lack of support for contentEncoding. However the import in 3.1/3.2 should lead to a bytes type and an encode decorator. > > > ### Checklist > > - [x] Follow our [Code of Conduct](https://github.com/microsoft/typespec/blob/main/CODE_OF_CONDUCT.md) > - [x] Read the [docs](https://typespec.io/docs/). > - [x] Check that there isn't already an issue that request the same feature to avoid creating a duplicate. > > make sure you run the format and lint commands before each commit. > use conventional commits. > run `npx @chronus/chronus add` to add a bugfix changelog entry when done with the changes. > > ## Comments on the Issue (you are @copilot in this section) > > > >
- Fixes microsoft/typespec#9150 --- ✨ Let Copilot coding agent [set things up for you](https://github.com/microsoft/typespec/issues/new?title=✨+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot) — coding agent works faster and does higher quality work when set up for your repo. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: baywet <7905502+baywet@users.noreply.github.com> Co-authored-by: Vincent Biret Co-authored-by: Timothee Guerin --- ...ntent-encoding-import-2025-12-5-18-32-55.md | 7 +++++++ .../convert/generators/generate-types.ts | 6 ++++++ .../cli/actions/convert/utils/decorators.ts | 8 ++++++++ .../test/tsp-openapi3/data-types.test.ts | 18 ++++++++++++++++++ .../test/tsp-openapi3/generate-type.test.ts | 6 ++++-- 5 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 .chronus/changes/fix-base64-content-encoding-import-2025-12-5-18-32-55.md diff --git a/.chronus/changes/fix-base64-content-encoding-import-2025-12-5-18-32-55.md b/.chronus/changes/fix-base64-content-encoding-import-2025-12-5-18-32-55.md new file mode 100644 index 00000000000..7a9fea578ae --- /dev/null +++ b/.chronus/changes/fix-base64-content-encoding-import-2025-12-5-18-32-55.md @@ -0,0 +1,7 @@ +--- +changeKind: fix +packages: + - "@typespec/openapi3" +--- + +Import OpenAPI 3.1/3.2 schemas with contentEncoding: base64 as bytes type with `@encode("base64", string)` decorator diff --git a/packages/openapi3/src/cli/actions/convert/generators/generate-types.ts b/packages/openapi3/src/cli/actions/convert/generators/generate-types.ts index 43c03ee6b25..c0564847f40 100644 --- a/packages/openapi3/src/cli/actions/convert/generators/generate-types.ts +++ b/packages/openapi3/src/cli/actions/convert/generators/generate-types.ts @@ -572,6 +572,12 @@ function getNumberType(schema: SupportedOpenAPISchema): string { function getStringType(schema: SupportedOpenAPISchema): string { const format = schema.format ?? ""; + + // Handle contentEncoding: base64 for OpenAPI 3.1+ (indicates binary data encoded as base64 string) + if ("contentEncoding" in schema && schema.contentEncoding === "base64") { + return "bytes"; + } + let type = "string"; switch (format) { case "binary": diff --git a/packages/openapi3/src/cli/actions/convert/utils/decorators.ts b/packages/openapi3/src/cli/actions/convert/utils/decorators.ts index 58de4bef5cd..dd16a85b624 100644 --- a/packages/openapi3/src/cli/actions/convert/utils/decorators.ts +++ b/packages/openapi3/src/cli/actions/convert/utils/decorators.ts @@ -305,6 +305,14 @@ function getStringSchemaDecorators(schema: OpenAPI3Schema | OpenAPISchema3_1) { decorators.push({ name: "format", args: [schema.format] }); } + // Handle contentEncoding: base64 for OpenAPI 3.1+ (indicates binary data encoded as base64 string) + if ("contentEncoding" in schema && schema.contentEncoding === "base64") { + decorators.push({ + name: "encode", + args: [createTSValue(`"base64"`), createTSValue("string")], + }); + } + return decorators; } diff --git a/packages/openapi3/test/tsp-openapi3/data-types.test.ts b/packages/openapi3/test/tsp-openapi3/data-types.test.ts index abdb8d4f731..ba44e9f8234 100644 --- a/packages/openapi3/test/tsp-openapi3/data-types.test.ts +++ b/packages/openapi3/test/tsp-openapi3/data-types.test.ts @@ -75,6 +75,24 @@ describe("converts top-level schemas", () => { ]); }); + it("handles contentEncoding base64 as bytes with @encode decorator", async () => { + const serviceNamespace = await tspForOpenAPI3({ + schemas: { + Base64Encoded: { + type: "string", + contentEncoding: "base64", + } as any, + }, + }); + + const scalars = serviceNamespace.scalars; + /* @encode("base64", string) scalar Base64Encoded extends bytes; */ + expect(scalars.get("Base64Encoded")?.baseScalar?.name).toBe("bytes"); + expectDecorators(scalars.get("Base64Encoded")!.decorators, [ + { name: "encode", args: ["base64", { kind: "Scalar", name: "string" }] }, + ]); + }); + it("handles arrays", async () => { const serviceNamespace = await tspForOpenAPI3({ schemas: { diff --git a/packages/openapi3/test/tsp-openapi3/generate-type.test.ts b/packages/openapi3/test/tsp-openapi3/generate-type.test.ts index 45bfb031111..38033dc131c 100644 --- a/packages/openapi3/test/tsp-openapi3/generate-type.test.ts +++ b/packages/openapi3/test/tsp-openapi3/generate-type.test.ts @@ -3,10 +3,10 @@ import { formatTypeSpec } from "@typespec/compiler"; import { strictEqual } from "node:assert"; import { beforeAll, describe, it } from "vitest"; import { Context, createContext } from "../../src/cli/actions/convert/utils/context.js"; -import { OpenAPI3Document, OpenAPI3Schema, Refable } from "../../src/types.js"; +import { OpenAPI3Document, OpenAPI3Schema, OpenAPISchema3_1, Refable } from "../../src/types.js"; interface TestScenario { - schema: Refable; + schema: Refable; expected: string; } @@ -62,6 +62,8 @@ const testScenarios: TestScenario[] = [ }, { schema: { type: "string", format: "binary" }, expected: "bytes" }, { schema: { type: "string", format: "byte" }, expected: "bytes" }, + // OpenAPI 3.1+ contentEncoding: base64 should be bytes + { schema: { type: "string", contentEncoding: "base64" }, expected: "bytes" }, { schema: { type: "string", format: "date" }, expected: "plainDate" }, { schema: { type: "string", format: "date-time" }, expected: "utcDateTime" }, { schema: { type: "string", format: "duration" }, expected: "duration" }, From dd00983d7211761ddf52c7ef0614df884e993a7b Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Mon, 8 Dec 2025 10:24:02 -0800 Subject: [PATCH 13/40] Add External property to InputType to preserve original type information (#9153) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - [x] Add `InputExternalTypeMetadata` interface to TypeScript for external type metadata - [x] Add `external` property to TypeScript `InputTypeBase` interface - [x] Create `fromSdkExternalTypeInfo` helper function to convert TCGC external info - [x] Update `fromSdkType` to use helper function instead of extracting inline - [x] Remove separate `InputExternalType` handling and preserve original type structure - [x] Create C# `InputExternalTypeMetadata` class - [x] Add `External` property to C# `InputType` class - [x] Create `InputExternalTypeMetadataConverter` for JSON serialization - [x] Update all type converters to handle External property - [x] Delete `InputExternalType` class and converter - [x] Update `TypeFactory.CreateCSharpTypeCore` to check External property first - [x] Update `CreateExternalType` to accept `InputExternalTypeMetadata` - [x] Update tests to validate external property is set on original types - [x] Add optional `InputExternalTypeMetadata` parameter to all applicable InputFactory methods (Union, Array, Dictionary, Model, Enum) - [x] Add comprehensive tests for External property deserialization (Union, Model, Array, Dictionary, Enum) - [x] Run all tests to ensure no regressions
Original prompt > > ---- > > *This section details on the original issue you should resolve* > > Include original input type information for external types > For the case of DFE in particular, we expect tsp like the following: > ``` > @doc("Expression model for DataFactory expressions") > model DfeExpressionModel { > @doc("The type of expression") > type: "Expression"; > @doc("The expression value") > value: string; > } > > // DataFactoryElement alternate type pattern > @alternateType({identity: "Azure.Core.Expressions.DataFactoryElement"}, "csharp") > union Dfe { > T, > DfeExpressionModel > } > > @doc("Model with DataFactoryElement properties") > model DataFactoryElementModel { > @doc("String property with DFE pattern") > stringProperty: Dfe; > > @doc("Int property with DFE pattern") > intProperty: Dfe; > > @doc("Bool property with DFE pattern") > boolProperty: Dfe; > > @doc("String array property with DFE pattern") > stringArrayProperty: Dfe; > } > ``` > > Right now, the union is replaced in the C# emitter with an external type. We should include a property on the external type that contains the original input type that was replaced. This is needed for DFE as we need to be able to get the union variant that represents the generic argument. There may be similar scenarios for other alternate types so we should just include the original input type as a property on the constructed external type in the emitter. We will need to update the C# InputExternalType to have a corresponding `Original` property of type `InputType`. > > ## Comments on the Issue (you are @copilot in this section) > > > >
- Fixes microsoft/typespec#9152 --- 💬 We'd love your input! Share your thoughts on Copilot coding agent in our [2 minute survey](https://gh.io/copilot-coding-agent-survey). --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com> Co-authored-by: jolov --- .../emitter/src/lib/type-converter.ts | 52 ++--- .../emitter/src/type/input-type.ts | 21 +- .../emitter/test/Unit/type-converter.test.ts | 28 ++- ...alType.cs => InputExternalTypeMetadata.cs} | 8 +- .../src/InputTypes/InputType.cs | 1 + .../Serialization/InputArrayTypeConverter.cs | 7 +- .../InputDateTimeTypeConverter.cs | 6 +- .../InputDictionaryTypeConverter.cs | 5 +- .../InputDurationTypeConverter.cs | 6 +- .../Serialization/InputEnumTypeConverter.cs | 5 +- ... => InputExternalTypeMetadataConverter.cs} | 35 ++-- .../Serialization/InputModelTypeConverter.cs | 3 + .../InputPrimitiveTypeConverter.cs | 7 +- .../Serialization/InputTypeConverter.cs | 2 - .../Serialization/InputUnionTypeConverter.cs | 5 +- .../TypeSpecInputNullableTypeConverter.cs | 5 +- .../test/TypeSpecInputConverterTests.cs | 185 ++++++++++++++++++ .../src/TypeFactory.cs | 19 +- .../ModelProviders/ModelProviderTests.cs | 15 +- .../test/common/InputFactory.cs | 76 ++++--- 20 files changed, 382 insertions(+), 109 deletions(-) rename packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/{InputExternalType.cs => InputExternalTypeMetadata.cs} (79%) rename packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/{InputExternalTypeConverter.cs => InputExternalTypeMetadataConverter.cs} (52%) diff --git a/packages/http-client-csharp/emitter/src/lib/type-converter.ts b/packages/http-client-csharp/emitter/src/lib/type-converter.ts index f49918d1fc6..f6b31db5578 100644 --- a/packages/http-client-csharp/emitter/src/lib/type-converter.ts +++ b/packages/http-client-csharp/emitter/src/lib/type-converter.ts @@ -29,7 +29,7 @@ import { InputDurationType, InputEnumType, InputEnumValueType, - InputExternalType, + InputExternalTypeMetadata, InputLiteralType, InputModelProperty, InputModelType, @@ -81,19 +81,13 @@ export function fromSdkType( return retVar as any; } - // Check if this type references an external type - if ((sdkType as any).external) { - retVar = fromSdkExternalType(sdkContext, sdkType); - sdkContext.__typeCache.updateSdkTypeReferences(sdkType, retVar); - return retVar as any; - } - switch (sdkType.kind) { case "nullable": const nullableType: InputNullableType = { kind: "nullable", type: fromSdkType(sdkContext, sdkType.type, sdkProperty, namespace), namespace: sdkType.namespace, + external: fromSdkExternalTypeInfo(sdkType), }; retVar = nullableType; break; @@ -146,6 +140,7 @@ export function fromSdkType( name: "tuple", crossLanguageDefinitionId: "", decorators: sdkType.decorators, + external: fromSdkExternalTypeInfo(sdkType), }; retVar = tupleType; break; @@ -165,6 +160,7 @@ export function fromSdkType( name: "credential", crossLanguageDefinitionId: "", decorators: sdkType.decorators, + external: fromSdkExternalTypeInfo(sdkType), }; retVar = credentialType; break; @@ -200,6 +196,7 @@ function fromSdkModelType( summary: modelType.summary, discriminatorValue: modelType.discriminatorValue, decorators: decorators, + external: fromSdkExternalTypeInfo(modelType), } as InputModelType; sdkContext.__typeCache.updateSdkTypeReferences(modelType, inputModelType); @@ -313,6 +310,7 @@ function createEnumType( // constantType.usage, TODO - constant type now does not have usage. TCGC will add it later usage: sdkType.kind === "enum" ? sdkType.usage : UsageFlags.None, decorators: sdkType.decorators, + external: fromSdkExternalTypeInfo(sdkType), }; sdkContext.__typeCache.updateSdkTypeReferences(sdkType, inputEnumType); @@ -340,6 +338,7 @@ function fromSdkDateTimeType( crossLanguageDefinitionId: dateTimeType.crossLanguageDefinitionId, baseType: dateTimeType.baseType ? fromSdkType(sdkContext, dateTimeType.baseType) : undefined, decorators: dateTimeType.decorators, + external: fromSdkExternalTypeInfo(dateTimeType), }; } @@ -355,6 +354,7 @@ function fromSdkDurationType( crossLanguageDefinitionId: durationType.crossLanguageDefinitionId, baseType: durationType.baseType ? fromSdkType(sdkContext, durationType.baseType) : undefined, decorators: durationType.decorators, + external: fromSdkExternalTypeInfo(durationType), }; } @@ -369,6 +369,7 @@ function fromSdkBuiltInType( crossLanguageDefinitionId: builtInType.crossLanguageDefinitionId, baseType: builtInType.baseType ? fromSdkType(sdkContext, builtInType.baseType) : undefined, decorators: builtInType.decorators, + external: fromSdkExternalTypeInfo(builtInType), }; } @@ -385,6 +386,7 @@ function fromUnionType(sdkContext: CSharpEmitterContext, union: SdkUnionType): I variantTypes: variantTypes, namespace: union.namespace, decorators: union.decorators, + external: fromSdkExternalTypeInfo(union), }; } @@ -447,6 +449,7 @@ function fromSdkDictionaryType( keyType: fromSdkType(sdkContext, dictionaryType.keyType), valueType: fromSdkType(sdkContext, dictionaryType.valueType), decorators: dictionaryType.decorators, + external: fromSdkExternalTypeInfo(dictionaryType), }; } @@ -460,6 +463,7 @@ function fromSdkArrayType( valueType: fromSdkType(sdkContext, arrayType.valueType), crossLanguageDefinitionId: arrayType.crossLanguageDefinitionId, decorators: arrayType.decorators, + external: fromSdkExternalTypeInfo(arrayType), }; } @@ -471,20 +475,6 @@ function fromSdkEndpointType(): InputPrimitiveType { }; } -function fromSdkExternalType( - sdkContext: CSharpEmitterContext, - sdkType: SdkType, -): InputExternalType { - const external = (sdkType as any).external; - return { - kind: "external", - identity: external.identity, - package: external.package, - minVersion: external.minVersion, - decorators: sdkType.decorators, - }; -} - /** * @beta */ @@ -510,3 +500,21 @@ export function getAllModelDecorators( return Array.from(decoratorMap.values()); } + +/** + * Converts TCGC external type information to InputExternalTypeMetadata + * @param sdkType - The SDK type that may have external type information + * @returns InputExternalTypeMetadata if the type has external info, undefined otherwise + */ +function fromSdkExternalTypeInfo(sdkType: SdkType): InputExternalTypeMetadata | undefined { + const external = (sdkType as any).external; + if (!external) { + return undefined; + } + + return { + identity: external.identity, + package: external.package, + minVersion: external.minVersion, + }; +} diff --git a/packages/http-client-csharp/emitter/src/type/input-type.ts b/packages/http-client-csharp/emitter/src/type/input-type.ts index 4164350ea21..628aad29e37 100644 --- a/packages/http-client-csharp/emitter/src/type/input-type.ts +++ b/packages/http-client-csharp/emitter/src/type/input-type.ts @@ -16,6 +16,16 @@ import { InputParameterScope } from "./input-parameter-scope.js"; import { InputServiceMethod } from "./input-service-method.js"; import { RequestLocation } from "./request-location.js"; +/** + * External type information for types that map to external library types. + * @beta + */ +export interface InputExternalTypeMetadata { + identity: string; + package?: string; + minVersion?: string; +} + /** * The input client type for the CSharp emitter. * @beta @@ -54,6 +64,7 @@ interface InputTypeBase extends DecoratedType { summary?: string; doc?: string; deprecation?: string; + external?: InputExternalTypeMetadata; } export type InputType = @@ -67,8 +78,7 @@ export type InputType = | InputEnumValueType | InputArrayType | InputDictionaryType - | InputNullableType - | InputExternalType; + | InputNullableType; export interface InputPrimitiveType extends InputTypeBase { kind: SdkBuiltInKinds; @@ -274,10 +284,3 @@ export interface InputDictionaryType extends InputTypeBase { keyType: InputType; valueType: InputType; } - -export interface InputExternalType extends InputTypeBase { - kind: "external"; - identity: string; - package?: string; - minVersion?: string; -} diff --git a/packages/http-client-csharp/emitter/test/Unit/type-converter.test.ts b/packages/http-client-csharp/emitter/test/Unit/type-converter.test.ts index abe4b08e49e..081708c903f 100644 --- a/packages/http-client-csharp/emitter/test/Unit/type-converter.test.ts +++ b/packages/http-client-csharp/emitter/test/Unit/type-converter.test.ts @@ -127,11 +127,18 @@ describe("External types", () => { const prop = testModel.properties.find((p) => p.name === "prop"); ok(prop, "prop should exist"); - // The type should be an external type - strictEqual(prop.type.kind, "external"); - strictEqual((prop.type as any).identity, "Azure.Core.Expressions.DataFactoryExpression"); - strictEqual((prop.type as any).package, "Azure.Core.Expressions"); - strictEqual((prop.type as any).minVersion, "1.0.0"); + // The type should remain a union but with external info + strictEqual(prop.type.kind, "union"); + ok((prop.type as any).external, "Type should have external info"); + strictEqual( + (prop.type as any).external.identity, + "Azure.Core.Expressions.DataFactoryExpression", + ); + strictEqual((prop.type as any).external.package, "Azure.Core.Expressions"); + strictEqual((prop.type as any).external.minVersion, "1.0.0"); + // Verify union variants are preserved + ok((prop.type as any).variantTypes, "Union should have variant types"); + strictEqual((prop.type as any).variantTypes.length, 2, "Union should have 2 variant types"); }); it("should convert external type on model", async () => { @@ -165,10 +172,11 @@ describe("External types", () => { const jsonElementProp = testModel.properties.find((p) => p.name === "jsonElement"); ok(jsonElementProp, "jsonElement property should exist"); - // The type should be an external type - strictEqual(jsonElementProp.type.kind, "external"); - strictEqual((jsonElementProp.type as any).identity, "System.Text.Json.JsonElement"); - strictEqual((jsonElementProp.type as any).package, "System.Text.Json"); - strictEqual((jsonElementProp.type as any).minVersion, "8.0.0"); + // The type should remain a model but with external info + strictEqual(jsonElementProp.type.kind, "model"); + ok((jsonElementProp.type as any).external, "Type should have external info"); + strictEqual((jsonElementProp.type as any).external.identity, "System.Text.Json.JsonElement"); + strictEqual((jsonElementProp.type as any).external.package, "System.Text.Json"); + strictEqual((jsonElementProp.type as any).external.minVersion, "8.0.0"); }); }); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputExternalType.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputExternalTypeMetadata.cs similarity index 79% rename from packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputExternalType.cs rename to packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputExternalTypeMetadata.cs index 422c33ed2fd..37b7fb9955c 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputExternalType.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputExternalTypeMetadata.cs @@ -4,17 +4,17 @@ namespace Microsoft.TypeSpec.Generator.Input { /// - /// Represents an external type reference in the input model. + /// External type information for types that map to external library types. /// - public sealed class InputExternalType : InputType + public sealed class InputExternalTypeMetadata { /// - /// Construct a new instance + /// Construct a new instance /// /// The fully qualified name of the external type. /// The package that exports the external type. /// The minimum version of the package. - public InputExternalType(string identity, string? package, string? minVersion) : base("external") + public InputExternalTypeMetadata(string identity, string? package, string? minVersion) { Identity = identity; Package = package; diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputType.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputType.cs index efafe4186e3..f29410ac780 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputType.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputType.cs @@ -21,6 +21,7 @@ protected InputType(string name) public string Name { get; internal set; } public IReadOnlyList Decorators { get; internal set; } = new List(); + public InputExternalTypeMetadata? External { get; internal set; } internal InputType GetCollectionEquivalent(InputType inputType) { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputArrayTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputArrayTypeConverter.cs index b27cfd575dd..c7b2eaf884f 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputArrayTypeConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputArrayTypeConverter.cs @@ -28,13 +28,15 @@ public static InputArrayType CreateListType(ref Utf8JsonReader reader, string? i string? crossLanguageDefinitionId = null; InputType? valueType = null; IReadOnlyList? decorators = null; + InputExternalTypeMetadata? external = null; while (reader.TokenType != JsonTokenType.EndObject) { var isKnownProperty = reader.TryReadReferenceId(ref id) || reader.TryReadString("name", ref name) || reader.TryReadString("crossLanguageDefinitionId", ref crossLanguageDefinitionId) || reader.TryReadComplexType("valueType", options, ref valueType) - || reader.TryReadComplexType("decorators", options, ref decorators); + || reader.TryReadComplexType("decorators", options, ref decorators) + || reader.TryReadComplexType("external", options, ref external); if (!isKnownProperty) { @@ -45,7 +47,8 @@ public static InputArrayType CreateListType(ref Utf8JsonReader reader, string? i valueType = valueType ?? throw new JsonException("List must have element type"); var listType = new InputArrayType(name ?? "Array", crossLanguageDefinitionId ?? string.Empty, valueType) { - Decorators = decorators ?? [] + Decorators = decorators ?? [], + External = external }; if (id != null) { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDateTimeTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDateTimeTypeConverter.cs index 1ebb73d5971..9cec784fcff 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDateTimeTypeConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDateTimeTypeConverter.cs @@ -29,6 +29,7 @@ public static InputDateTimeType CreateDateTimeType(ref Utf8JsonReader reader, st InputPrimitiveType? wireType = null; IReadOnlyList? decorators = null; InputDateTimeType? baseType = null; + InputExternalTypeMetadata? external = null; while (reader.TokenType != JsonTokenType.EndObject) { @@ -38,7 +39,8 @@ public static InputDateTimeType CreateDateTimeType(ref Utf8JsonReader reader, st || reader.TryReadString("encode", ref encode) || reader.TryReadComplexType("wireType", options, ref wireType) || reader.TryReadComplexType("baseType", options, ref baseType) - || reader.TryReadComplexType("decorators", options, ref decorators); + || reader.TryReadComplexType("decorators", options, ref decorators) + || reader.TryReadComplexType("external", options, ref external); if (!isKnownProperty) { @@ -52,7 +54,7 @@ public static InputDateTimeType CreateDateTimeType(ref Utf8JsonReader reader, st wireType = wireType ?? throw new JsonException("DateTime type must have wireType"); var dateTimeType = Enum.TryParse(encode, ignoreCase: true, out var encodeKind) - ? new InputDateTimeType(encodeKind, name, crossLanguageDefinitionId, wireType, baseType) { Decorators = decorators ?? [] } + ? new InputDateTimeType(encodeKind, name, crossLanguageDefinitionId, wireType, baseType) { Decorators = decorators ?? [], External = external } : throw new JsonException($"Encoding of DateTime type {encode} is unknown."); if (id != null) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDictionaryTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDictionaryTypeConverter.cs index 4a7737426a6..429cb5f396f 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDictionaryTypeConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDictionaryTypeConverter.cs @@ -28,12 +28,14 @@ public static InputDictionaryType CreateDictionaryType(ref Utf8JsonReader reader InputType? keyType = null; InputType? valueType = null; IReadOnlyList? decorators = null; + InputExternalTypeMetadata? external = null; while (reader.TokenType != JsonTokenType.EndObject) { var isKnownProperty = reader.TryReadReferenceId(ref id) || reader.TryReadComplexType("keyType", options, ref keyType) || reader.TryReadComplexType("valueType", options, ref valueType) - || reader.TryReadComplexType("decorators", options, ref decorators); + || reader.TryReadComplexType("decorators", options, ref decorators) + || reader.TryReadComplexType("external", options, ref external); if (!isKnownProperty) { @@ -47,6 +49,7 @@ public static InputDictionaryType CreateDictionaryType(ref Utf8JsonReader reader var dictType = new InputDictionaryType("Dictionary", keyType, valueType) { Decorators = decorators ?? [], + External = external }; if (id != null) { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDurationTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDurationTypeConverter.cs index 789571e7302..3107ddc9f0c 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDurationTypeConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDurationTypeConverter.cs @@ -30,6 +30,7 @@ public static InputDurationType CreateDurationType(ref Utf8JsonReader reader, st InputPrimitiveType? wireType = null; IReadOnlyList? decorators = null; InputDurationType? baseType = null; + InputExternalTypeMetadata? external = null; while (reader.TokenType != JsonTokenType.EndObject) { @@ -39,7 +40,8 @@ public static InputDurationType CreateDurationType(ref Utf8JsonReader reader, st || reader.TryReadString("encode", ref encode) || reader.TryReadComplexType("wireType", options, ref wireType) || reader.TryReadComplexType("baseType", options, ref baseType) - || reader.TryReadComplexType("decorators", options, ref decorators); + || reader.TryReadComplexType("decorators", options, ref decorators) + || reader.TryReadComplexType("external", options, ref external); if (!isKnownProperty) { @@ -53,7 +55,7 @@ public static InputDurationType CreateDurationType(ref Utf8JsonReader reader, st wireType = wireType ?? throw new JsonException("Duration type must have wireType"); var dateTimeType = DurationKnownEncodingExtensions.TryParse(encode, out var encodeKind) - ? new InputDurationType(encodeKind.Value, name, crossLanguageDefinitionId, wireType, baseType) { Decorators = decorators ?? [] } + ? new InputDurationType(encodeKind.Value, name, crossLanguageDefinitionId, wireType, baseType) { Decorators = decorators ?? [], External = external } : throw new JsonException($"Encoding of Duration type {encode} is unknown."); if (id != null) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputEnumTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputEnumTypeConverter.cs index fa3fc2246b3..028ee85c25f 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputEnumTypeConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputEnumTypeConverter.cs @@ -60,6 +60,7 @@ public static InputEnumType CreateEnumType(ref Utf8JsonReader reader, string? id InputPrimitiveType? valueType = null; IReadOnlyList? values = null; IReadOnlyList? decorators = null; + InputExternalTypeMetadata? external = null; while (reader.TokenType != JsonTokenType.EndObject) { var isKnownProperty = reader.TryReadString("name", ref name) @@ -73,7 +74,8 @@ public static InputEnumType CreateEnumType(ref Utf8JsonReader reader, string? id || reader.TryReadBoolean("isFixed", ref isFixed) || reader.TryReadComplexType("valueType", options, ref valueType) || reader.TryReadComplexType("values", options, ref values) - || reader.TryReadComplexType("decorators", options, ref decorators); + || reader.TryReadComplexType("decorators", options, ref decorators) + || reader.TryReadComplexType("external", options, ref external); if (!isKnownProperty) { @@ -97,6 +99,7 @@ public static InputEnumType CreateEnumType(ref Utf8JsonReader reader, string? id enumType.ValueType = valueType ?? throw new JsonException("Enum must have valueType"); enumType.IsExtensible = !isFixed; enumType.Decorators = decorators ?? []; + enumType.External = external; return enumType; } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputExternalTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputExternalTypeMetadataConverter.cs similarity index 52% rename from packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputExternalTypeConverter.cs rename to packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputExternalTypeMetadataConverter.cs index 32cf22e3714..e31ab43d48d 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputExternalTypeConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputExternalTypeMetadataConverter.cs @@ -2,41 +2,45 @@ // Licensed under the MIT License. using System; -using System.Collections.Generic; using System.Text.Json; using System.Text.Json.Serialization; namespace Microsoft.TypeSpec.Generator.Input { - internal class InputExternalTypeConverter : JsonConverter + internal class InputExternalTypeMetadataConverter : JsonConverter { private readonly TypeSpecReferenceHandler _referenceHandler; - public InputExternalTypeConverter(TypeSpecReferenceHandler referenceHandler) + public InputExternalTypeMetadataConverter(TypeSpecReferenceHandler referenceHandler) { _referenceHandler = referenceHandler; } - public override InputExternalType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - => reader.ReadReferenceAndResolve(_referenceHandler.CurrentResolver) ?? CreateInputExternalType(ref reader, null, options, _referenceHandler.CurrentResolver); + public override InputExternalTypeMetadata? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + { + return null; + } - public override void Write(Utf8JsonWriter writer, InputExternalType value, JsonSerializerOptions options) + return reader.ReadReferenceAndResolve(_referenceHandler.CurrentResolver) ?? CreateInputExternalTypeMetadata(ref reader, null, options, _referenceHandler.CurrentResolver); + } + + public override void Write(Utf8JsonWriter writer, InputExternalTypeMetadata value, JsonSerializerOptions options) => throw new NotSupportedException("Writing not supported"); - public static InputExternalType CreateInputExternalType(ref Utf8JsonReader reader, string? id, JsonSerializerOptions options, ReferenceResolver resolver) + public static InputExternalTypeMetadata CreateInputExternalTypeMetadata(ref Utf8JsonReader reader, string? id, JsonSerializerOptions options, ReferenceResolver resolver) { string? identity = null; string? package = null; string? minVersion = null; - IReadOnlyList? decorators = null; while (reader.TokenType != JsonTokenType.EndObject) { var isKnownProperty = reader.TryReadReferenceId(ref id) || reader.TryReadString("identity", ref identity) || reader.TryReadString("package", ref package) - || reader.TryReadString("minVersion", ref minVersion) - || reader.TryReadComplexType("decorators", options, ref decorators); + || reader.TryReadString("minVersion", ref minVersion); if (!isKnownProperty) { @@ -44,19 +48,16 @@ public static InputExternalType CreateInputExternalType(ref Utf8JsonReader reade } } - identity = identity ?? throw new JsonException("InputExternalType must have identity"); + identity = identity ?? throw new JsonException("InputExternalTypeMetadata must have identity"); - var externalType = new InputExternalType(identity, package, minVersion) - { - Decorators = decorators ?? [] - }; + var externalTypeProperties = new InputExternalTypeMetadata(identity, package, minVersion); if (id != null) { - resolver.AddReference(id, externalType); + resolver.AddReference(id, externalTypeProperties); } - return externalType; + return externalTypeProperties; } } } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputModelTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputModelTypeConverter.cs index 18b691d77e7..32ae2cc5aee 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputModelTypeConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputModelTypeConverter.cs @@ -72,6 +72,7 @@ internal static InputModelType CreateModelType(ref Utf8JsonReader reader, string bool modelAsStruct = false; IReadOnlyList? decorators = null; InputSerializationOptions? serializationOptions = null; + InputExternalTypeMetadata? external = null; // read all possible properties and throw away the unknown properties while (reader.TokenType != JsonTokenType.EndObject) @@ -92,6 +93,7 @@ internal static InputModelType CreateModelType(ref Utf8JsonReader reader, string || reader.TryReadComplexType("discriminatedSubtypes", options, ref discriminatedSubtypes) || reader.TryReadComplexType("decorators", options, ref decorators) || reader.TryReadComplexType("serializationOptions", options, ref serializationOptions) + || reader.TryReadComplexType("external", options, ref external) || reader.TryReadBoolean(nameof(InputModelType.ModelAsStruct), ref modelAsStruct); // TODO -- change this to fetch from the decorator list instead when the decorator is ready if (!isKnownProperty) @@ -138,6 +140,7 @@ internal static InputModelType CreateModelType(ref Utf8JsonReader reader, string MarkModelsAsDynamicRecursive(model, []); } } + model.External = external; // if this model has a base, it means this model is a derived model of the base model, add it into the list. if (baseModel != null) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputPrimitiveTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputPrimitiveTypeConverter.cs index 61c6b7e6cd2..00f9ec2c179 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputPrimitiveTypeConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputPrimitiveTypeConverter.cs @@ -29,6 +29,7 @@ public static InputPrimitiveType CreatePrimitiveType(ref Utf8JsonReader reader, string? encode = null; InputPrimitiveType? baseType = null; IReadOnlyList? decorators = null; + InputExternalTypeMetadata? external = null; while (reader.TokenType != JsonTokenType.EndObject) { var isKnownProperty = reader.TryReadReferenceId(ref id) @@ -37,7 +38,8 @@ public static InputPrimitiveType CreatePrimitiveType(ref Utf8JsonReader reader, || reader.TryReadString("crossLanguageDefinitionId", ref crossLanguageDefinitionId) || reader.TryReadString("encode", ref encode) || reader.TryReadComplexType("baseType", options, ref baseType) - || reader.TryReadComplexType("decorators", options, ref decorators); + || reader.TryReadComplexType("decorators", options, ref decorators) + || reader.TryReadComplexType("external", options, ref external); if (!isKnownProperty) { @@ -56,7 +58,8 @@ public static InputPrimitiveType CreatePrimitiveType(ref Utf8JsonReader reader, var primitiveType = new InputPrimitiveType(primitiveTypeKind, name, crossLanguageDefinitionId, encode, baseType) { - Decorators = decorators ?? [] + Decorators = decorators ?? [], + External = external }; if (id != null) { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputTypeConverter.cs index 98fb96a7dd1..eef96ae8571 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputTypeConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputTypeConverter.cs @@ -57,7 +57,6 @@ private static InputType CreateInputType(ref Utf8JsonReader reader, JsonSerializ private const string UtcDateTimeKind = "utcDateTime"; private const string OffsetDateTimeKind = "offsetDateTime"; private const string DurationKind = "duration"; - private const string ExternalKind = "external"; private static InputType CreateDerivedType(ref Utf8JsonReader reader, string? id, string? kind, string? name, JsonSerializerOptions options, ReferenceResolver resolver) => kind switch { @@ -72,7 +71,6 @@ private static InputType CreateInputType(ref Utf8JsonReader reader, JsonSerializ UtcDateTimeKind or OffsetDateTimeKind => InputDateTimeTypeConverter.CreateDateTimeType(ref reader, id, name, options, resolver), DurationKind => InputDurationTypeConverter.CreateDurationType(ref reader, id, name, options, resolver), NullableKind => TypeSpecInputNullableTypeConverter.CreateNullableType(ref reader, id, name, options, resolver), - ExternalKind => InputExternalTypeConverter.CreateInputExternalType(ref reader, id, options, resolver), _ => InputPrimitiveTypeConverter.CreatePrimitiveType(ref reader, id, kind, name, options, resolver), }; } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputUnionTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputUnionTypeConverter.cs index b286b20d6bd..23c8cb8b31a 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputUnionTypeConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputUnionTypeConverter.cs @@ -37,11 +37,13 @@ public static InputUnionType CreateInputUnionType(ref Utf8JsonReader reader, str IReadOnlyList? variantTypes = null; IReadOnlyList? decorators = null; + InputExternalTypeMetadata? external = null; while (reader.TokenType != JsonTokenType.EndObject) { var isKnownProperty = reader.TryReadString("name", ref name) || reader.TryReadComplexType("variantTypes", options, ref variantTypes) - || reader.TryReadComplexType("decorators", options, ref decorators); + || reader.TryReadComplexType("decorators", options, ref decorators) + || reader.TryReadComplexType("external", options, ref external); if (!isKnownProperty) { @@ -56,6 +58,7 @@ public static InputUnionType CreateInputUnionType(ref Utf8JsonReader reader, str } union.VariantTypes = variantTypes; union.Decorators = decorators ?? []; + union.External = external; return union; } } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/TypeSpecInputNullableTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/TypeSpecInputNullableTypeConverter.cs index 815a946dc21..55c6e6d2d1a 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/TypeSpecInputNullableTypeConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/TypeSpecInputNullableTypeConverter.cs @@ -26,12 +26,14 @@ public static InputNullableType CreateNullableType(ref Utf8JsonReader reader, st { InputType? valueType = null; IReadOnlyList? decorators = null; + InputExternalTypeMetadata? external = null; while (reader.TokenType != JsonTokenType.EndObject) { var isKnownProperty = reader.TryReadReferenceId(ref id) || reader.TryReadString("name", ref name) || reader.TryReadComplexType("type", options, ref valueType) - || reader.TryReadComplexType("decorators", options, ref decorators); + || reader.TryReadComplexType("decorators", options, ref decorators) + || reader.TryReadComplexType("external", options, ref external); if (!isKnownProperty) { @@ -44,6 +46,7 @@ public static InputNullableType CreateNullableType(ref Utf8JsonReader reader, st var nullableType = new InputNullableType(valueType) { Decorators = decorators ?? [], + External = external }; if (id != null) { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/test/TypeSpecInputConverterTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/test/TypeSpecInputConverterTests.cs index 1a2c31b7cba..a73ae78abc3 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/test/TypeSpecInputConverterTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/test/TypeSpecInputConverterTests.cs @@ -436,5 +436,190 @@ public void LoadsClientWithSubclientInitializedBy() Assert.AreEqual("ParentClient", subClient.Parent!.Name, "SubClient's parent should be ParentClient"); Assert.AreEqual(0, subClient.Children.Count, "SubClient should have no children"); } + + [Test] + public void DeserializeUnionWithExternalMetadata() + { + var json = @"{ + ""$id"": ""1"", + ""kind"": ""union"", + ""name"": ""TestUnion"", + ""variantTypes"": [ + { ""$id"": ""2"", ""kind"": ""string"", ""name"": ""string"", ""crossLanguageDefinitionId"": ""TypeSpec.string"" } + ], + ""external"": { + ""identity"": ""Azure.Core.Expressions.DataFactoryElement"", + ""package"": ""Azure.Core.Expressions"", + ""minVersion"": ""1.0.0"" + } + }"; + + var referenceHandler = new TypeSpecReferenceHandler(); + var options = new JsonSerializerOptions + { + AllowTrailingCommas = true, + Converters = + { + new InputTypeConverter(referenceHandler), + new InputUnionTypeConverter(referenceHandler), + new InputPrimitiveTypeConverter(referenceHandler), + new InputExternalTypeMetadataConverter(referenceHandler) + } + }; + + var union = JsonSerializer.Deserialize(json, options); + Assert.IsNotNull(union); + Assert.IsNotNull(union!.External); + Assert.AreEqual("Azure.Core.Expressions.DataFactoryElement", union.External!.Identity); + Assert.AreEqual("Azure.Core.Expressions", union.External.Package); + Assert.AreEqual("1.0.0", union.External.MinVersion); + Assert.AreEqual(1, union.VariantTypes.Count); + } + + [Test] + public void DeserializeModelWithExternalMetadata() + { + var json = @"{ + ""$id"": ""1"", + ""kind"": ""model"", + ""name"": ""TestModel"", + ""namespace"": ""Test.Models"", + ""crossLanguageDefinitionId"": ""Test.Models.TestModel"", + ""usage"": ""None"", + ""properties"": [], + ""external"": { + ""identity"": ""System.Text.Json.JsonElement"", + ""package"": ""System.Text.Json"", + ""minVersion"": ""8.0.0"" + } + }"; + + var referenceHandler = new TypeSpecReferenceHandler(); + var options = new JsonSerializerOptions + { + AllowTrailingCommas = true, + Converters = + { + new InputTypeConverter(referenceHandler), + new InputModelTypeConverter(referenceHandler), + new InputExternalTypeMetadataConverter(referenceHandler) + } + }; + + var model = JsonSerializer.Deserialize(json, options); + Assert.IsNotNull(model); + Assert.IsNotNull(model!.External); + Assert.AreEqual("System.Text.Json.JsonElement", model.External!.Identity); + Assert.AreEqual("System.Text.Json", model.External.Package); + Assert.AreEqual("8.0.0", model.External.MinVersion); + } + + [Test] + public void DeserializeArrayWithExternalMetadata() + { + var json = @"{ + ""$id"": ""1"", + ""kind"": ""array"", + ""name"": ""TestArray"", + ""crossLanguageDefinitionId"": ""TestArray"", + ""valueType"": { ""$id"": ""2"", ""kind"": ""string"", ""name"": ""string"", ""crossLanguageDefinitionId"": ""TypeSpec.string"" }, + ""external"": { + ""identity"": ""System.Collections.Generic.IList"" + } + }"; + + var referenceHandler = new TypeSpecReferenceHandler(); + var options = new JsonSerializerOptions + { + AllowTrailingCommas = true, + Converters = + { + new InputTypeConverter(referenceHandler), + new InputArrayTypeConverter(referenceHandler), + new InputPrimitiveTypeConverter(referenceHandler), + new InputExternalTypeMetadataConverter(referenceHandler) + } + }; + + var array = JsonSerializer.Deserialize(json, options); + Assert.IsNotNull(array); + Assert.IsNotNull(array!.External); + Assert.AreEqual("System.Collections.Generic.IList", array.External!.Identity); + Assert.IsNull(array.External.Package); + Assert.IsNull(array.External.MinVersion); + } + + [Test] + public void DeserializeDictionaryWithExternalMetadata() + { + var json = @"{ + ""$id"": ""1"", + ""kind"": ""dict"", + ""keyType"": { ""$id"": ""2"", ""kind"": ""string"", ""name"": ""string"", ""crossLanguageDefinitionId"": ""TypeSpec.string"" }, + ""valueType"": { ""$id"": ""3"", ""kind"": ""string"", ""name"": ""string"", ""crossLanguageDefinitionId"": ""TypeSpec.string"" }, + ""external"": { + ""identity"": ""System.Collections.Generic.IDictionary"", + ""package"": ""System.Collections"" + } + }"; + + var referenceHandler = new TypeSpecReferenceHandler(); + var options = new JsonSerializerOptions + { + AllowTrailingCommas = true, + Converters = + { + new InputTypeConverter(referenceHandler), + new InputDictionaryTypeConverter(referenceHandler), + new InputPrimitiveTypeConverter(referenceHandler), + new InputExternalTypeMetadataConverter(referenceHandler) + } + }; + + var dictionary = JsonSerializer.Deserialize(json, options); + Assert.IsNotNull(dictionary); + Assert.IsNotNull(dictionary!.External); + Assert.AreEqual("System.Collections.Generic.IDictionary", dictionary.External!.Identity); + Assert.AreEqual("System.Collections", dictionary.External.Package); + Assert.IsNull(dictionary.External.MinVersion); + } + + [Test] + public void DeserializeEnumWithExternalMetadata() + { + var json = @"{ + ""$id"": ""1"", + ""kind"": ""enum"", + ""name"": ""TestEnum"", + ""namespace"": ""Test.Models"", + ""crossLanguageDefinitionId"": ""Test.Models.TestEnum"", + ""valueType"": { ""$id"": ""2"", ""kind"": ""string"", ""name"": ""string"", ""crossLanguageDefinitionId"": ""TypeSpec.string"" }, + ""values"": [], + ""isFixed"": true, + ""external"": { + ""identity"": ""System.DayOfWeek"" + } + }"; + + var referenceHandler = new TypeSpecReferenceHandler(); + var options = new JsonSerializerOptions + { + AllowTrailingCommas = true, + Converters = + { + new InputTypeConverter(referenceHandler), + new InputEnumTypeConverter(referenceHandler), + new InputPrimitiveTypeConverter(referenceHandler), + new InputExternalTypeMetadataConverter(referenceHandler) + } + }; + + var enumType = JsonSerializer.Deserialize(json, options); + Assert.IsNotNull(enumType); + Assert.IsNotNull(enumType!.External); + Assert.AreEqual("System.DayOfWeek", enumType.External!.Identity); + Assert.IsNull(enumType.External.Package); + Assert.IsNull(enumType.External.MinVersion); + } } } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/TypeFactory.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/TypeFactory.cs index 2ea693751cb..705a331086a 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/TypeFactory.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/TypeFactory.cs @@ -79,6 +79,12 @@ protected internal TypeFactory() protected virtual CSharpType? CreateCSharpTypeCore(InputType inputType) { + // Check if this type has external type information + if (inputType.External != null) + { + return CreateExternalType(inputType.External); + } + CSharpType? type; switch (inputType) { @@ -125,9 +131,6 @@ protected internal TypeFactory() case InputNullableType nullableType: type = CreateCSharpType(nullableType.Type)?.WithNullable(true); break; - case InputExternalType externalType: - type = CreateExternalType(externalType); - break; default: type = CreatePrimitiveCSharpTypeCore(inputType); break; @@ -233,14 +236,14 @@ protected internal TypeFactory() => EnumProvider.Create(enumType, declaringType); /// - /// Factory method for creating a based on an external type reference . + /// Factory method for creating a based on external type properties. /// - /// The to convert. + /// The to convert. /// A representing the external type, or null if the type cannot be resolved. - private CSharpType? CreateExternalType(InputExternalType externalType) + private CSharpType? CreateExternalType(InputExternalTypeMetadata externalProperties) { // Try to create a framework type from the fully qualified name - var frameworkType = CreateFrameworkType(externalType.Identity); + var frameworkType = CreateFrameworkType(externalProperties.Identity); if (frameworkType != null) { return new CSharpType(frameworkType); @@ -250,7 +253,7 @@ protected internal TypeFactory() // Report a diagnostic to inform the user CodeModelGenerator.Instance.Emitter.ReportDiagnostic( "unsupported-external-type", - $"External type '{externalType.Identity}' is not currently supported."); + $"External type '{externalProperties.Identity}' is not currently supported."); return null; } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelProviderTests.cs index b23436d0002..a3f6f3c0f00 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelProviderTests.cs @@ -1163,7 +1163,10 @@ public void ConstantPropertiesAccessibility( public void ExternalTypeModelUsedAsProperty() { // Test a model decorated with alternateType that references System.Uri - var externalType = InputFactory.External("System.Uri"); + var externalType = InputFactory.Union( + [InputPrimitiveType.String], + "ExternalUnion", + new InputExternalTypeMetadata("System.Uri", null, null)); var modelWithExternal = InputFactory.Model("ExternalModel"); // Create a model that uses the external type as a property @@ -1197,7 +1200,10 @@ public void ExternalTypeModelUsedAsProperty() public void ExternalTypePropertyIsResolved() { // Test a property decorated with alternateType - var externalType = InputFactory.External("System.Net.IPAddress", "System.Net.Primitives", "4.3.0"); + var externalType = InputFactory.Union( + [InputPrimitiveType.String], + "ExternalUnion", + new InputExternalTypeMetadata("System.Net.IPAddress", "System.Net.Primitives", "4.3.0")); var model = InputFactory.Model( "ModelWithExternalProperty", @@ -1229,7 +1235,10 @@ public void ExternalTypePropertyIsResolved() public void UnsupportedExternalTypeEmitsDiagnostic() { // Test an external type that cannot be resolved (non-framework type) - var externalType = InputFactory.External("Azure.Core.Expressions.DataFactoryExpression"); + var externalType = InputFactory.Union( + [InputPrimitiveType.String], + "ExternalUnion", + new InputExternalTypeMetadata("Azure.Core.Expressions.DataFactoryExpression", null, null)); var model = InputFactory.Model( "ModelWithUnsupportedExternal", diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/common/InputFactory.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/common/InputFactory.cs index dce2b4141a2..3492ce53eed 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/common/InputFactory.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/common/InputFactory.cs @@ -98,7 +98,8 @@ public static InputEnumType StringEnum( string access = "public", InputModelTypeUsage usage = InputModelTypeUsage.Input | InputModelTypeUsage.Output, bool isExtensible = false, - string clientNamespace = "Sample.Models") + string clientNamespace = "Sample.Models", + InputExternalTypeMetadata? external = null) { var enumValues = new List(); var enumType = Enum( @@ -108,7 +109,8 @@ public static InputEnumType StringEnum( access: access, usage: usage, isExtensible: isExtensible, - clientNamespace: clientNamespace); + clientNamespace: clientNamespace, + external: external); foreach (var (valueName, value) in values) { @@ -124,7 +126,8 @@ public static InputEnumType Int32Enum( string access = "public", InputModelTypeUsage usage = InputModelTypeUsage.Input | InputModelTypeUsage.Output, bool isExtensible = false, - string clientNamespace = "Sample.Models") + string clientNamespace = "Sample.Models", + InputExternalTypeMetadata? external = null) { var enumValues = new List(); var enumType = Enum( @@ -134,7 +137,8 @@ public static InputEnumType Int32Enum( access: access, usage: usage, isExtensible: isExtensible, - clientNamespace: clientNamespace); + clientNamespace: clientNamespace, + external: external); foreach (var (valueName, value) in values) { @@ -150,7 +154,8 @@ public static InputEnumType Float32Enum( string access = "public", InputModelTypeUsage usage = InputModelTypeUsage.Input | InputModelTypeUsage.Output, bool isExtensible = false, - string clientNamespace = "Sample.Models") + string clientNamespace = "Sample.Models", + InputExternalTypeMetadata? external = null) { var enumValues = new List(); var enumType = Enum( @@ -160,7 +165,8 @@ public static InputEnumType Float32Enum( access: access, usage: usage, isExtensible: isExtensible, - clientNamespace: clientNamespace); + clientNamespace: clientNamespace, + external: external); foreach (var (valueName, value) in values) { @@ -176,7 +182,8 @@ public static InputEnumType Float64Enum( string access = "public", InputModelTypeUsage usage = InputModelTypeUsage.Input | InputModelTypeUsage.Output, bool isExtensible = false, - string clientNamespace = "Sample.Models") + string clientNamespace = "Sample.Models", + InputExternalTypeMetadata? external = null) { var enumValues = new List(); var enumType = Enum( @@ -186,7 +193,8 @@ public static InputEnumType Float64Enum( access: access, usage: usage, isExtensible: isExtensible, - clientNamespace: clientNamespace); + clientNamespace: clientNamespace, + external: external); foreach (var (valueName, value) in values) { @@ -203,8 +211,10 @@ private static InputEnumType Enum( string access = "public", InputModelTypeUsage usage = InputModelTypeUsage.Output | InputModelTypeUsage.Input, bool isExtensible = false, - string clientNamespace = "Sample.Models") - => new InputEnumType( + string clientNamespace = "Sample.Models", + InputExternalTypeMetadata? external = null) + { + var enumType = new InputEnumType( name, clientNamespace, name, @@ -216,6 +226,12 @@ private static InputEnumType Enum( underlyingType, values, isExtensible); + if (external != null) + { + enumType.External = external; + } + return enumType; + } public static InputModelProperty Property( string name, @@ -449,7 +465,8 @@ public static InputModelType Model( IDictionary? discriminatedModels = null, IEnumerable? derivedModels = null, InputModelProperty? discriminatorProperty = null, - bool isDynamicModel = false) + bool isDynamicModel = false, + InputExternalTypeMetadata? external = null) { IEnumerable propertiesList = properties ?? [Property("StringProperty", InputPrimitiveType.String)]; @@ -480,22 +497,42 @@ discriminatedModels is null _addDerivedModelMethod.Invoke(baseModel, new object[] { model }); } + if (external != null) + { + model.External = external; + } + return model; } - public static InputType Array(InputType elementType) + public static InputType Array(InputType elementType, InputExternalTypeMetadata? external = null) { - return new InputArrayType("list", "list", elementType); + var array = new InputArrayType("list", "list", elementType); + if (external != null) + { + array.External = external; + } + return array; } - public static InputType Dictionary(InputType valueType, InputType? keyType = null) + public static InputType Dictionary(InputType valueType, InputType? keyType = null, InputExternalTypeMetadata? external = null) { - return new InputDictionaryType("dictionary", keyType ?? InputPrimitiveType.String, valueType); + var dictionary = new InputDictionaryType("dictionary", keyType ?? InputPrimitiveType.String, valueType); + if (external != null) + { + dictionary.External = external; + } + return dictionary; } - public static InputType Union(IList types, string name = "union") + public static InputType Union(IList types, string name = "union", InputExternalTypeMetadata? external = null) { - return new InputUnionType(name, [.. types]); + var union = new InputUnionType(name, [.. types]); + if (external != null) + { + union.External = external; + } + return union; } public static InputBasicServiceMethod BasicServiceMethod( @@ -629,11 +666,6 @@ public static InputServiceMethodResponse ServiceMethodResponse(InputType? type, return new InputServiceMethodResponse(type, resultSegments); } - public static InputExternalType External(string identity, string? package = null, string? minVersion = null) - { - return new InputExternalType(identity, package, minVersion); - } - private static readonly Dictionary> _childClientsCache = new(); public static InputClient Client(string name, string clientNamespace = "Sample", string? doc = null, IEnumerable? methods = null, IEnumerable? parameters = null, InputClient? parent = null, string? crossLanguageDefinitionId = null, IEnumerable? apiVersions = null, InputClientInitializedBy initializedBy = InputClientInitializedBy.Default) From 679a0253fcf9f434df5b37f52bccb0b3eba94a44 Mon Sep 17 00:00:00 2001 From: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com> Date: Mon, 8 Dec 2025 15:53:10 -0800 Subject: [PATCH 14/40] Fix external metadata (#9161) --- .../InputExternalTypeMetadataConverter.cs | 28 +++++++------------ .../Serialization/TypeSpecSerialization.cs | 1 + .../tspCodeModel.json | 23 +++++++++++++++ .../test/TypeSpecInputConverterTests.cs | 28 +++++++++++++++---- 4 files changed, 57 insertions(+), 23 deletions(-) create mode 100644 packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/test/TestData/TypeSpecInputConverterTests/LoadsModelWithExternalMetadataEndToEnd/tspCodeModel.json diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputExternalTypeMetadataConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputExternalTypeMetadataConverter.cs index e31ab43d48d..3c8653d9c6c 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputExternalTypeMetadataConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputExternalTypeMetadataConverter.cs @@ -9,13 +9,6 @@ namespace Microsoft.TypeSpec.Generator.Input { internal class InputExternalTypeMetadataConverter : JsonConverter { - private readonly TypeSpecReferenceHandler _referenceHandler; - - public InputExternalTypeMetadataConverter(TypeSpecReferenceHandler referenceHandler) - { - _referenceHandler = referenceHandler; - } - public override InputExternalTypeMetadata? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.Null) @@ -23,24 +16,28 @@ public InputExternalTypeMetadataConverter(TypeSpecReferenceHandler referenceHand return null; } - return reader.ReadReferenceAndResolve(_referenceHandler.CurrentResolver) ?? CreateInputExternalTypeMetadata(ref reader, null, options, _referenceHandler.CurrentResolver); + return CreateInputExternalTypeMetadata(ref reader); } public override void Write(Utf8JsonWriter writer, InputExternalTypeMetadata value, JsonSerializerOptions options) => throw new NotSupportedException("Writing not supported"); - public static InputExternalTypeMetadata CreateInputExternalTypeMetadata(ref Utf8JsonReader reader, string? id, JsonSerializerOptions options, ReferenceResolver resolver) + public static InputExternalTypeMetadata CreateInputExternalTypeMetadata(ref Utf8JsonReader reader) { string? identity = null; string? package = null; string? minVersion = null; + if (reader.TokenType == JsonTokenType.StartObject) + { + reader.Read(); + } + while (reader.TokenType != JsonTokenType.EndObject) { - var isKnownProperty = reader.TryReadReferenceId(ref id) - || reader.TryReadString("identity", ref identity) - || reader.TryReadString("package", ref package) - || reader.TryReadString("minVersion", ref minVersion); + var isKnownProperty = reader.TryReadString("identity", ref identity) + || reader.TryReadString("package", ref package) + || reader.TryReadString("minVersion", ref minVersion); if (!isKnownProperty) { @@ -52,11 +49,6 @@ public static InputExternalTypeMetadata CreateInputExternalTypeMetadata(ref Utf8 var externalTypeProperties = new InputExternalTypeMetadata(identity, package, minVersion); - if (id != null) - { - resolver.AddReference(id, externalTypeProperties); - } - return externalTypeProperties; } } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/TypeSpecSerialization.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/TypeSpecSerialization.cs index a9d96ae4e84..22aeb61683c 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/TypeSpecSerialization.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/TypeSpecSerialization.cs @@ -72,6 +72,7 @@ public static class TypeSpecSerialization new TypeSpecInputExampleValueConverter(), new TypeSpecInputParameterExampleConverter(), new TypeSpecInputOperationExampleConverter(), + new InputExternalTypeMetadataConverter(), } }; diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/test/TestData/TypeSpecInputConverterTests/LoadsModelWithExternalMetadataEndToEnd/tspCodeModel.json b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/test/TestData/TypeSpecInputConverterTests/LoadsModelWithExternalMetadataEndToEnd/tspCodeModel.json new file mode 100644 index 00000000000..d6e07cf5265 --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/test/TestData/TypeSpecInputConverterTests/LoadsModelWithExternalMetadataEndToEnd/tspCodeModel.json @@ -0,0 +1,23 @@ +{ + "$id": "1", + "name": "TestNamespace", + "models": [ + { + "$id": "2", + "kind": "model", + "name": "ExternalModel", + "namespace": "TestNamespace", + "crossLanguageDefinitionId": "TestNamespace.ExternalModel", + "usage": "None", + "properties": [], + "external": { + "identity": "System.Text.Json.JsonElement", + "package": "System.Text.Json", + "minVersion": "8.0.0" + } + } + ], + "clients": [], + "enums": [] +} + diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/test/TypeSpecInputConverterTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/test/TypeSpecInputConverterTests.cs index a73ae78abc3..a8a59f31433 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/test/TypeSpecInputConverterTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/test/TypeSpecInputConverterTests.cs @@ -463,7 +463,7 @@ public void DeserializeUnionWithExternalMetadata() new InputTypeConverter(referenceHandler), new InputUnionTypeConverter(referenceHandler), new InputPrimitiveTypeConverter(referenceHandler), - new InputExternalTypeMetadataConverter(referenceHandler) + new InputExternalTypeMetadataConverter() } }; @@ -502,7 +502,7 @@ public void DeserializeModelWithExternalMetadata() { new InputTypeConverter(referenceHandler), new InputModelTypeConverter(referenceHandler), - new InputExternalTypeMetadataConverter(referenceHandler) + new InputExternalTypeMetadataConverter() } }; @@ -537,7 +537,7 @@ public void DeserializeArrayWithExternalMetadata() new InputTypeConverter(referenceHandler), new InputArrayTypeConverter(referenceHandler), new InputPrimitiveTypeConverter(referenceHandler), - new InputExternalTypeMetadataConverter(referenceHandler) + new InputExternalTypeMetadataConverter() } }; @@ -572,7 +572,7 @@ public void DeserializeDictionaryWithExternalMetadata() new InputTypeConverter(referenceHandler), new InputDictionaryTypeConverter(referenceHandler), new InputPrimitiveTypeConverter(referenceHandler), - new InputExternalTypeMetadataConverter(referenceHandler) + new InputExternalTypeMetadataConverter() } }; @@ -610,7 +610,7 @@ public void DeserializeEnumWithExternalMetadata() new InputTypeConverter(referenceHandler), new InputEnumTypeConverter(referenceHandler), new InputPrimitiveTypeConverter(referenceHandler), - new InputExternalTypeMetadataConverter(referenceHandler) + new InputExternalTypeMetadataConverter() } }; @@ -621,5 +621,23 @@ public void DeserializeEnumWithExternalMetadata() Assert.IsNull(enumType.External.Package); Assert.IsNull(enumType.External.MinVersion); } + + [Test] + public void LoadsModelWithExternalMetadataEndToEnd() + { + var directory = Helpers.GetAssetFileOrDirectoryPath(false); + // this tspCodeModel.json contains a partial part of the full tspCodeModel.json + var content = File.ReadAllText(Path.Combine(directory, "tspCodeModel.json")); + var inputNamespace = TypeSpecSerialization.Deserialize(content); + + Assert.IsNotNull(inputNamespace); + + var externalModel = inputNamespace!.Models.SingleOrDefault(m => m.Name == "ExternalModel"); + Assert.IsNotNull(externalModel); + Assert.IsNotNull(externalModel!.External, "External metadata should be populated"); + Assert.AreEqual("System.Text.Json.JsonElement", externalModel.External!.Identity); + Assert.AreEqual("System.Text.Json", externalModel.External.Package); + Assert.AreEqual("8.0.0", externalModel.External.MinVersion); + } } } From c3eb1725d14051c00073da5ef540c0b41f6b5226 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 9 Dec 2025 17:52:39 +0000 Subject: [PATCH 15/40] fix(openapi3): emit @encode decorator for anyOf/oneOf with unixtime format (#9164) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When importing OpenAPI schemas with `anyOf`/`oneOf` containing `{type: "integer", format: "unixtime"}` and `{type: "null"}`, the converter was dropping the `@encode(DateTimeKnownEncoding.unixTimestamp, integer)` decorator. **Before:** ```yaml finished_at: anyOf: - type: integer format: unixtime - type: "null" ``` ```typespec finished_at?: utcDateTime | null // Missing @encode decorator ``` **After:** ```typespec @encode(DateTimeKnownEncoding.unixTimestamp, integer) finished_at?: utcDateTime | null ``` ## Changes - **`decorators.ts`**: Modified `getDecoratorsForSchema` to extract `format` property from `anyOf`/`oneOf` members when not present at schema root - **Tests**: Added coverage for both `anyOf` and `oneOf` union variants with unixtime format - **Changelog**: Added fix entry for @typespec/openapi3
Original prompt > > ---- > > *This section details on the original issue you should resolve* > > converter - import anyOf unixtime missed decorator > When importing this OpenAPI schema > > ```yaml > components: > schemas: > FineTuningJob: > type: object > properties: > created_at: > type: integer > description: The Unix timestamp (in seconds) for when the fine-tuning job was created. > format: unixtime > ``` > > I get the following result > > ```typespec > @encode(DateTimeKnownEncoding.unixTimestamp, integer) created_at: utcDateTime > ``` > > However, if the schema is instead an anyOf with null, I get the following TypeSpec result, which misses the encode decorator > > ```yaml > components: > schemas: > FineTuningJob: > type: object > properties: > finished_at: > anyOf: > - type: integer > description: The Unix timestamp (in seconds) for when the fine-tuning job was finished. The value will be null if the fine-tuning job is still running. > format: unixtime > - type: "null" > ``` > > ```typespec > finished_at: utcDateTime | null > ``` > > The decorator should be present whenever a union type with null is emitted. > > run the formatting script before any commit. > when you're done with all the changes, run `npx @chronus/chronus add` to add a bugfix entry to the changelog. > use conventional commits. > > ## Comments on the Issue (you are @copilot in this section) > > > >
- Fixes microsoft/typespec#9163 --- 💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more [Copilot coding agent tips](https://gh.io/copilot-coding-agent-tips) in the docs. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: baywet <7905502+baywet@users.noreply.github.com> Co-authored-by: Vincent Biret Co-authored-by: Timothee Guerin --- ...-unixtime-decorator-2025-12-09-16-54-20.md | 7 ++ .../cli/actions/convert/utils/decorators.ts | 31 ++++++- .../tsp-openapi3/convert-openapi3-doc.test.ts | 87 +++++++++++++++++++ 3 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 .chronus/changes/fix-anyof-unixtime-decorator-2025-12-09-16-54-20.md diff --git a/.chronus/changes/fix-anyof-unixtime-decorator-2025-12-09-16-54-20.md b/.chronus/changes/fix-anyof-unixtime-decorator-2025-12-09-16-54-20.md new file mode 100644 index 00000000000..c7cc8c897b2 --- /dev/null +++ b/.chronus/changes/fix-anyof-unixtime-decorator-2025-12-09-16-54-20.md @@ -0,0 +1,7 @@ +--- +changeKind: fix +packages: + - "@typespec/openapi3" +--- + +Import OpenAPI schemas with anyOf/oneOf containing unixtime format correctly emits `@encode(DateTimeKnownEncoding.unixTimestamp, integer)` decorator for nullable utcDateTime properties diff --git a/packages/openapi3/src/cli/actions/convert/utils/decorators.ts b/packages/openapi3/src/cli/actions/convert/utils/decorators.ts index dd16a85b624..ec230d84b73 100644 --- a/packages/openapi3/src/cli/actions/convert/utils/decorators.ts +++ b/packages/openapi3/src/cli/actions/convert/utils/decorators.ts @@ -172,8 +172,35 @@ export function getDecoratorsForSchema( : schema.type; // Handle unixtime format with @encode decorator - if (schema.format === "unixtime") { - decorators.push(...getUnixtimeSchemaDecorators(effectiveType)); + // Check both direct format and format from anyOf/oneOf members + let formatToUse = schema.format; + let typeForFormat = effectiveType; + + // If format is not directly on the schema, check anyOf/oneOf members for unixtime format + if (!formatToUse) { + const unionMembers = schema.anyOf || schema.oneOf; + if (unionMembers) { + for (const member of unionMembers) { + if ("$ref" in member) continue; + // Check if this is a non-null member with unixtime format + if (member.format === "unixtime" && member.type !== "null") { + formatToUse = member.format; + // Extract effective type from member (handle type arrays) + const memberType = Array.isArray(member.type) + ? member.type.find((t) => t !== "null") + : member.type; + // Only use if we found a valid type + if (memberType) { + typeForFormat = memberType; + } + break; + } + } + } + } + + if (formatToUse === "unixtime") { + decorators.push(...getUnixtimeSchemaDecorators(typeForFormat)); } switch (effectiveType) { diff --git a/packages/openapi3/test/tsp-openapi3/convert-openapi3-doc.test.ts b/packages/openapi3/test/tsp-openapi3/convert-openapi3-doc.test.ts index dbb55791909..2933a1280f4 100644 --- a/packages/openapi3/test/tsp-openapi3/convert-openapi3-doc.test.ts +++ b/packages/openapi3/test/tsp-openapi3/convert-openapi3-doc.test.ts @@ -407,4 +407,91 @@ describe("unixtime format conversion", () => { "Expected 'created?: string' but got: " + tsp, ); }); + + it("should convert anyOf with integer unixtime and null to utcDateTime | null with @encode decorator", async () => { + const tsp = await convertOpenAPI3Document({ + openapi: "3.1.0", + info: { + title: "Test Service", + version: "0.0.0", + }, + paths: {}, + components: { + schemas: { + Foo: { + type: "object", + properties: { + finished_at: { + anyOf: [ + { + type: "integer", + format: "unixtime", + }, + { + type: "null", + }, + ], + }, + }, + }, + }, + }, + }); + + // Should contain "@encode(DateTimeKnownEncoding.unixTimestamp, integer)" and "finished_at?: utcDateTime | null" + strictEqual( + tsp.includes("@encode(DateTimeKnownEncoding.unixTimestamp, integer)"), + true, + "Expected '@encode(DateTimeKnownEncoding.unixTimestamp, integer)' but got: " + tsp, + ); + strictEqual( + tsp.includes("finished_at?: utcDateTime | null"), + true, + "Expected 'finished_at?: utcDateTime | null' but got: " + tsp, + ); + }); + + it("should convert oneOf with integer unixtime and null to utcDateTime | null with @encode decorator", async () => { + const tsp = await convertOpenAPI3Document({ + openapi: "3.1.0", + info: { + title: "Test Service", + version: "0.0.0", + }, + paths: {}, + components: { + schemas: { + Foo: { + type: "object", + properties: { + started_at: { + oneOf: [ + { + type: "integer", + format: "unixtime", + }, + { + type: "null", + }, + ], + }, + }, + }, + }, + }, + }); + + // Should contain "@encode(DateTimeKnownEncoding.unixTimestamp, integer)" and "@oneOf" and "started_at?: utcDateTime | null" + strictEqual( + tsp.includes("@encode(DateTimeKnownEncoding.unixTimestamp, integer)"), + true, + "Expected '@encode(DateTimeKnownEncoding.unixTimestamp, integer)' but got: " + tsp, + ); + strictEqual(tsp.includes("@oneOf"), true, "Expected '@oneOf' but got: " + tsp); + strictEqual( + tsp.includes("started_at?: utcDateTime | null"), + true, + "Expected 'started_at?: utcDateTime | null' but got: " + tsp, + ); + }); }); From 6439e09cb3624d7047bb055f861f20917f3a117f Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Tue, 9 Dec 2025 13:13:21 -0500 Subject: [PATCH 16/40] Add release notes for 1.7.0 release (#9165) --- .../docs/release-notes/release-2025-12-09.md | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 website/src/content/docs/docs/release-notes/release-2025-12-09.md diff --git a/website/src/content/docs/docs/release-notes/release-2025-12-09.md b/website/src/content/docs/docs/release-notes/release-2025-12-09.md new file mode 100644 index 00000000000..da0d02e248e --- /dev/null +++ b/website/src/content/docs/docs/release-notes/release-2025-12-09.md @@ -0,0 +1,53 @@ +--- +title: "1.7.0" +releaseDate: 2025-12-09 +version: "1.7.0" +--- + +# 1.7.0 + +## Features + +### @typespec/compiler + +- [#9002](https://github.com/microsoft/typespec/pull/9002) Add `commaDelimited` and `newlineDelimited` values to `ArrayEncoding` enum for serializing arrays with comma and newline delimiters +- [#8942](https://github.com/microsoft/typespec/pull/8942) - Add 'exit' final event for linter rules + - Support 'async' in linter definition and async function as callback for 'exit' event. +- [#9024](https://github.com/microsoft/typespec/pull/9024) [API] Add `node` to `SourceModel` type +- [#8619](https://github.com/microsoft/typespec/pull/8619) Add support for escaping param like tags(`@param`, `@prop`, etc.) identifier with backtick in doc comments to allow special characters + +### @typespec/http + +- [#8962](https://github.com/microsoft/typespec/pull/8962) support documentation on union variants for response descriptions + +### @typespec/openapi3 + +- [#9002](https://github.com/microsoft/typespec/pull/9002) Add `commaDelimited` and `newlineDelimited` values to `ArrayEncoding` enum for serializing arrays with comma and newline delimiters + +### @typespec/json-schema + +- [#9038](https://github.com/microsoft/typespec/pull/9038) Add discriminator support and polymorphic models strategy option + - Automatically injects discriminator property into base models with `@discriminator` decorator + - Marks discriminator property as required in generated schemas + - New `polymorphic-models-strategy` emitter option with three strategies: + - `ignore`: Emit as regular object schema (default) + - `oneOf`: Emit oneOf schema for closed discriminated unions + - `anyOf`: Emit anyOf schema for open discriminated unions + - Includes discriminator.mapping in oneOf/anyOf schemas for improved validation + +## Bug Fixes + +### @typespec/compiler + +- [#8917](https://github.com/microsoft/typespec/pull/8917) Add security warning to tsp init CLI documentation for external templates (#8916) +- [#8997](https://github.com/microsoft/typespec/pull/8997) UnusedUsing Diagnostics are reported as warning instead of hint when there are linters defined in tspconfig.yaml + +### @typespec/http + +- [#8961](https://github.com/microsoft/typespec/pull/8961) Support nested unions in operation return types + +### @typespec/openapi3 + +- [#9151](https://github.com/microsoft/typespec/pull/9151) Import OpenAPI 3.1/3.2 schemas with contentEncoding: base64 as bytes type with `@encode("base64", string)` decorator +- [#9076](https://github.com/microsoft/typespec/pull/9076) Respect `@externalDocs` on properties +- [#8961](https://github.com/microsoft/typespec/pull/8961) Support nested unions in operation return types From ec260f553096bbab23ed4411aff0575cf7896819 Mon Sep 17 00:00:00 2001 From: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com> Date: Tue, 9 Dec 2025 10:24:49 -0800 Subject: [PATCH 17/40] Use CSharpType rather than Type for serialization hooks (#9166) For framework types that are generic where the arg may be a non-framework type, we lose the generic type arg information when using Type. --- .../MrwSerializationTypeDefinition.cs | 106 +++++++++++------- .../src/ScmTypeFactory.cs | 4 +- 2 files changed, 70 insertions(+), 40 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs index 38006af94d6..4eb94e9ba34 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs @@ -1822,44 +1822,49 @@ private MethodBodyStatement CreateValueSerializationStatement( SerializationFormat serializationFormat, ValueExpression value) { - // append the `.Value` if needed (when the type is nullable and a value type) - value = value.NullableStructValue(type); - - // now we just need to focus on how we serialize a value - if (type.IsFrameworkType) - return ScmCodeModelGenerator.Instance.TypeFactory.SerializeJsonValue(type.FrameworkType, value, _utf8JsonWriterSnippet, _mrwOptionsParameterSnippet, serializationFormat); - - if (!type.IsEnum) - return _utf8JsonWriterSnippet.WriteObjectValue(value.As(type), options: _mrwOptionsParameterSnippet); - - if (type.IsStruct) //is extensible - { - if (type.UnderlyingEnumType.Equals(typeof(string))) - return _utf8JsonWriterSnippet.WriteStringValue(value.Invoke(nameof(ToString))); - - return _utf8JsonWriterSnippet.WriteNumberValue(value.Invoke($"ToSerial{type.UnderlyingEnumType.Name}")); - } - else - { - if (type.UnderlyingEnumType.Equals(typeof(int))) - // when the fixed enum is implemented as int, we cast to the value - return _utf8JsonWriterSnippet.WriteNumberValue(value.CastTo(type.UnderlyingEnumType)); - - if (type.UnderlyingEnumType.Equals(typeof(string))) - return _utf8JsonWriterSnippet.WriteStringValue(value.Invoke($"ToSerial{type.UnderlyingEnumType.Name}")); - - return _utf8JsonWriterSnippet.WriteNumberValue(value.Invoke($"ToSerial{type.UnderlyingEnumType.Name}")); - } + return ScmCodeModelGenerator.Instance.TypeFactory.SerializeJsonValue(type, value, _utf8JsonWriterSnippet, _mrwOptionsParameterSnippet, serializationFormat); } internal static MethodBodyStatement SerializeJsonValueCore( - Type valueType, + CSharpType valueType, ValueExpression value, ScopedApi utf8JsonWriter, ScopedApi mrwOptionsParameter, SerializationFormat serializationFormat) { - MethodBodyStatement? statement = valueType switch + // append the `.Value` if needed (when the type is nullable and a value type) + value = value.NullableStructValue(valueType); + + // Handle enums + if (valueType.IsEnum) + { + if (valueType.IsStruct) // extensible enum + { + if (valueType.UnderlyingEnumType.Equals(typeof(string))) + return utf8JsonWriter.WriteStringValue(value.Invoke(nameof(ToString))); + + return utf8JsonWriter.WriteNumberValue(value.Invoke($"ToSerial{valueType.UnderlyingEnumType.Name}")); + } + else // fixed enum + { + if (valueType.UnderlyingEnumType.Equals(typeof(int))) + // when the fixed enum is implemented as int, we cast to the value + return utf8JsonWriter.WriteNumberValue(value.CastTo(valueType.UnderlyingEnumType)); + + if (valueType.UnderlyingEnumType.Equals(typeof(string))) + return utf8JsonWriter.WriteStringValue(value.Invoke($"ToSerial{valueType.UnderlyingEnumType.Name}")); + + return utf8JsonWriter.WriteNumberValue(value.Invoke($"ToSerial{valueType.UnderlyingEnumType.Name}")); + } + } + + // Handle non-enum types + if (!valueType.IsFrameworkType) + return utf8JsonWriter.WriteObjectValue(value.As(valueType), options: mrwOptionsParameter); + + // Handle framework types + var frameworkType = valueType.FrameworkType; + MethodBodyStatement? statement = frameworkType switch { var t when t == typeof(JsonElement) => value.As().WriteTo(utf8JsonWriter), @@ -1868,7 +1873,7 @@ var t when ValueTypeIsInt(t) && serializationFormat == SerializationFormat.Int_S var t when ValueTypeIsNumber(t) => utf8JsonWriter.WriteNumberValue(value), var t when t == typeof(object) => - utf8JsonWriter.WriteObjectValue(value.As(valueType), mrwOptionsParameter), + utf8JsonWriter.WriteObjectValue(value.As(frameworkType), mrwOptionsParameter), var t when t == typeof(string) || t == typeof(char) || t == typeof(Guid) => utf8JsonWriter.WriteStringValue(value), var t when t == typeof(bool) => @@ -1876,13 +1881,13 @@ var t when ValueTypeIsNumber(t) => var t when t == typeof(byte[]) => utf8JsonWriter.WriteBase64StringValue(value, serializationFormat.ToFormatSpecifier()), var t when t == typeof(DateTimeOffset) || t == typeof(DateTime) || t == typeof(TimeSpan) => - SerializeDateTimeRelatedTypes(valueType, serializationFormat, value, utf8JsonWriter, mrwOptionsParameter), + SerializeDateTimeRelatedTypes(frameworkType, serializationFormat, value, utf8JsonWriter, mrwOptionsParameter), var t when t == typeof(IPAddress) => utf8JsonWriter.WriteStringValue(value.InvokeToString()), var t when t == typeof(Uri) => utf8JsonWriter.WriteStringValue(new MemberExpression(value, nameof(Uri.AbsoluteUri))), var t when t == typeof(BinaryData) => - SerializeBinaryData(valueType, serializationFormat, value, utf8JsonWriter), + SerializeBinaryData(frameworkType, serializationFormat, value, utf8JsonWriter), var t when t == typeof(Stream) => utf8JsonWriter.WriteBinaryData(BinaryDataSnippets.FromStream(value, false)), _ => null @@ -1894,7 +1899,6 @@ var t when ValueTypeIsNumber(t) => DiagnosticCodes.UnsupportedSerialization, $"Serialization of type {valueType.Name} is not supported.", severity: EmitterDiagnosticSeverity.Warning); - return utf8JsonWriter.WriteObjectValue(value.As(valueType), mrwOptionsParameter); } @@ -1902,16 +1906,42 @@ var t when ValueTypeIsNumber(t) => } internal static ValueExpression DeserializeJsonValueCore( - Type valueType, + CSharpType valueType, ScopedApi element, ScopedApi data, ScopedApi mrwOptions, SerializationFormat format) { - ValueExpression? exp = valueType switch + // Handle enums + if (valueType.IsEnum) + { + var underlyingValue = DeserializeJsonValueCore( + new CSharpType(valueType.UnderlyingEnumType!), + element, + data, + mrwOptions, + format); + return valueType.ToEnum(underlyingValue); + } + + // Handle nullable types + if (valueType.IsFrameworkType && valueType.FrameworkType == typeof(Nullable<>)) + { + return DeserializeJsonValueCore(valueType.Arguments[0], element, data, mrwOptions, format); + } + + // Handle non-framework types + if (!valueType.IsFrameworkType) + { + return GetDeserializationMethodInvocationForType(valueType, element, data, mrwOptions); + } + + // Handle framework types + var frameworkType = valueType.FrameworkType; + ValueExpression? exp = frameworkType switch { Type t when t == typeof(Uri) => - New.Instance(valueType, element.GetString()), + New.Instance(frameworkType, element.GetString()), Type t when t == typeof(IPAddress) => Static().Invoke(nameof(IPAddress.Parse), element.GetString()), Type t when t == typeof(BinaryData) => @@ -1965,7 +1995,7 @@ Type t when ValueTypeIsInt(t) => DiagnosticCodes.UnsupportedSerialization, $"Deserialization of type {valueType.Name} is not supported.", severity: EmitterDiagnosticSeverity.Warning); - return GetDeserializationMethodInvocationForType(new CSharpType(valueType), element, data, mrwOptions); + return GetDeserializationMethodInvocationForType(valueType, element, data, mrwOptions); } return exp; diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/ScmTypeFactory.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/ScmTypeFactory.cs index 13cc6d86e7f..de4cb276c3e 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/ScmTypeFactory.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/ScmTypeFactory.cs @@ -230,7 +230,7 @@ private ExtensibleEnumSerializationProvider[] CreateExtensibleEnumSerializations } public virtual ValueExpression DeserializeJsonValue( - Type valueType, + CSharpType valueType, ScopedApi element, ScopedApi data, ScopedApi mrwOptionsParameter, @@ -238,7 +238,7 @@ public virtual ValueExpression DeserializeJsonValue( => MrwSerializationTypeDefinition.DeserializeJsonValueCore(valueType, element, data, mrwOptionsParameter, format); public virtual MethodBodyStatement SerializeJsonValue( - Type valueType, + CSharpType valueType, ValueExpression value, ScopedApi utf8JsonWriter, ScopedApi mrwOptionsParameter, From 12a7ed4474dd2697eb02fc31d187527ad48e596d Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Tue, 9 Dec 2025 15:13:17 -0500 Subject: [PATCH 18/40] Remove test branch (#9157) --- eng/tsp-core/pipelines/publish.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/eng/tsp-core/pipelines/publish.yml b/eng/tsp-core/pipelines/publish.yml index b2d43f64177..30c8b574c29 100644 --- a/eng/tsp-core/pipelines/publish.yml +++ b/eng/tsp-core/pipelines/publish.yml @@ -6,8 +6,6 @@ trigger: - main # For patch releases - release/* - - upgrade/pool-images - paths: exclude: - packages/http-client-csharp From 1c3426f5b04ac2cb5700d2ca25babc8e60be0fbd Mon Sep 17 00:00:00 2001 From: Jorge Rangel <102122018+jorgerangel-msft@users.noreply.github.com> Date: Tue, 9 Dec 2025 14:38:59 -0600 Subject: [PATCH 19/40] fix: respect custom property & field nullability (#9167) fixes: https://github.com/Azure/azure-sdk-for-net/issues/54405 --- .../src/Utilities/CSharpTypeExtensions.cs | 7 +- .../ModelProviders/ModelCustomizationTests.cs | 80 +++++++++++++++++-- .../MockInputModel.cs | 2 +- .../MockInputModel.cs | 10 +++ .../MockInputModel.cs | 10 +++ .../MockInputModel.cs | 2 +- .../MockInputModel.cs | 2 +- 7 files changed, 99 insertions(+), 14 deletions(-) create mode 100644 packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CanChangeEnumNullableTypeModelProperty/MockInputModel.cs create mode 100644 packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CanChangeEnumTypeModelPropertyToNullable/MockInputModel.cs diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Utilities/CSharpTypeExtensions.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Utilities/CSharpTypeExtensions.cs index b62dc790b68..f7a7f22db7e 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Utilities/CSharpTypeExtensions.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Utilities/CSharpTypeExtensions.cs @@ -55,14 +55,9 @@ private static CSharpType EnsureNamespace(InputProperty? specProperty, CSharpTyp // Use the TypeFactory to get the correct namespace for the type which respects any customizations that have // been applied to the generated types. var newType = CodeModelGenerator.Instance.TypeFactory.CreateCSharpType(inputType); - if (specProperty?.IsRequired == false && newType?.IsCollection == false) - { - newType = newType.WithNullable(true); - } - if (newType != null) { - return newType; + return type.IsNullable ? newType.WithNullable(true) : newType; } } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs index bcc011f46a8..d97e46be381 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs @@ -302,7 +302,7 @@ public async Task CanChangeListOfModelToReadOnlyListOfModel() var elementType = listProp.Type.ElementType; Assert.AreEqual("global::Sample.Models.Foo", elementType.ToString()); Assert.AreEqual("Sample.Models", elementType.Namespace); - Assert.IsTrue(elementType.IsNullable); + Assert.IsFalse(elementType.IsNullable); } [Test] @@ -336,9 +336,9 @@ public async Task CanChangeListOfEnumToReadOnlyListOfEnum() Assert.IsTrue(listProp.Type.IsList); var elementType = listProp.Type.ElementType; - Assert.AreEqual("global::Sample.Models.Foo?", elementType.ToString()); + Assert.AreEqual("global::Sample.Models.Foo", elementType.ToString()); Assert.AreEqual("Sample.Models", elementType.Namespace); - Assert.IsTrue(elementType.IsNullable); + Assert.IsFalse(elementType.IsNullable); Assert.IsFalse(elementType.IsStruct); Assert.IsFalse(elementType.IsLiteral); } @@ -414,7 +414,7 @@ public async Task CanChangeDictionaryOfModelToReadOnlyDictionaryOfModel() var elementType = listProp.Type.ElementType; Assert.AreEqual("global::Sample.Models.Foo", elementType.ToString()); Assert.AreEqual("Sample.Models", elementType.Namespace); - Assert.IsTrue(elementType.IsNullable); + Assert.IsFalse(elementType.IsNullable); } [Test] @@ -483,7 +483,7 @@ public async Task CanChangeModelPropertyWithChangedNamespace() var modelProp = modelTypeProvider.CanonicalView.Properties[0]; Assert.AreEqual("Prop1", modelProp.Name); - Assert.IsTrue(modelProp.Type.IsNullable); + Assert.IsFalse(modelProp.Type.IsNullable); Assert.IsFalse(modelProp.Body.HasSetter); Assert.AreEqual("global::Updated.Namespace.Models.Foo", modelProp.Type.ToString()); Assert.AreEqual("Updated.Namespace.Models", modelProp.Type.Namespace); @@ -626,6 +626,76 @@ public async Task CanChangeEnumToExtensibleEnum() Assert.IsTrue(enumProvider.DeclarationModifiers.HasFlag(TypeSignatureModifiers.Public | TypeSignatureModifiers.Partial | TypeSignatureModifiers.Struct | TypeSignatureModifiers.ReadOnly)); } + [Test] + public async Task CanChangeEnumNullableTypeModelProperty() + { + var inputEnum = InputFactory.Int32Enum( + "Foo", + [("val1", 1), ("val2", 2), ("val3", 3)], + isExtensible: false + ); + var props = new[] + { + InputFactory.Property("Prop1", inputEnum), + }; + + var inputModel = InputFactory.Model("mockInputModel", properties: props); + + var mockGenerator = await MockHelpers.LoadMockGeneratorAsync( + inputModelTypes: [inputModel], + compilation: async () => await Helpers.GetCompilationFromDirectoryAsync()); + + var modelTypeProvider = mockGenerator.Object.OutputLibrary.TypeProviders.Single(t => t.Name == "MockInputModel"); + AssertCommon(modelTypeProvider, "Sample.Models", "MockInputModel"); + + // the property should be added to the custom code view + Assert.AreEqual(1, modelTypeProvider.CustomCodeView!.Properties.Count); + // the canonical type should be changed + Assert.AreEqual(1, modelTypeProvider.CanonicalView!.Properties.Count); + + var modelProp = modelTypeProvider.CanonicalView.Properties[0]; + Assert.AreEqual("Prop1", modelProp.Name); + Assert.IsFalse(modelProp.Type.IsNullable); + Assert.IsFalse(modelProp.Body.HasSetter); + Assert.AreEqual("global::Sample.Models.Foo", modelProp.Type.ToString()); + Assert.AreEqual("Sample.Models", modelProp.Type.Namespace); + } + + [Test] + public async Task CanChangeEnumTypeModelPropertyToNullable() + { + var inputEnum = InputFactory.Int32Enum( + "Foo", + [("val1", 1), ("val2", 2), ("val3", 3)], + isExtensible: false + ); + var props = new[] + { + InputFactory.Property("Prop1", inputEnum), + }; + + var inputModel = InputFactory.Model("mockInputModel", properties: props); + + var mockGenerator = await MockHelpers.LoadMockGeneratorAsync( + inputModelTypes: [inputModel], + compilation: async () => await Helpers.GetCompilationFromDirectoryAsync()); + + var modelTypeProvider = mockGenerator.Object.OutputLibrary.TypeProviders.Single(t => t.Name == "MockInputModel"); + AssertCommon(modelTypeProvider, "Sample.Models", "MockInputModel"); + + // the property should be added to the custom code view + Assert.AreEqual(1, modelTypeProvider.CustomCodeView!.Properties.Count); + // the canonical type should be changed + Assert.AreEqual(1, modelTypeProvider.CanonicalView!.Properties.Count); + + var modelProp = modelTypeProvider.CanonicalView.Properties[0]; + Assert.AreEqual("Prop1", modelProp.Name); + Assert.IsTrue(modelProp.Type.IsNullable); + Assert.IsFalse(modelProp.Body.HasSetter); + Assert.AreEqual("global::Sample.Models.Foo?", modelProp.Type.ToString()); + Assert.AreEqual("Sample.Models", modelProp.Type.Namespace); + } + [Test] public async Task CanChangeExtensibleEnumToEnum() { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CanChangeDictionaryOfModelToReadOnlyDictionaryOfModel/MockInputModel.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CanChangeDictionaryOfModelToReadOnlyDictionaryOfModel/MockInputModel.cs index 20abb7c90d7..f363ae062a4 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CanChangeDictionaryOfModelToReadOnlyDictionaryOfModel/MockInputModel.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CanChangeDictionaryOfModelToReadOnlyDictionaryOfModel/MockInputModel.cs @@ -6,5 +6,5 @@ namespace Sample.Models; public partial class MockInputModel { - public readonly IReadOnlyDictionary Prop1 { get; }; + public readonly IReadOnlyDictionary Prop1 { get; } } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CanChangeEnumNullableTypeModelProperty/MockInputModel.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CanChangeEnumNullableTypeModelProperty/MockInputModel.cs new file mode 100644 index 00000000000..561e17ffc7a --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CanChangeEnumNullableTypeModelProperty/MockInputModel.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using SampleTypeSpec; + +namespace Sample.Models; + +public partial class MockInputModel +{ + public Foo Prop1 { get; }; +} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CanChangeEnumTypeModelPropertyToNullable/MockInputModel.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CanChangeEnumTypeModelPropertyToNullable/MockInputModel.cs new file mode 100644 index 00000000000..a9d892ec6ec --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CanChangeEnumTypeModelPropertyToNullable/MockInputModel.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using SampleTypeSpec; + +namespace Sample.Models; + +public partial class MockInputModel +{ + public Foo? Prop1 { get; }; +} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CanChangeListOfModelToReadOnlyListOfModel/MockInputModel.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CanChangeListOfModelToReadOnlyListOfModel/MockInputModel.cs index b9defff36b1..e5e7aeb1c3d 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CanChangeListOfModelToReadOnlyListOfModel/MockInputModel.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CanChangeListOfModelToReadOnlyListOfModel/MockInputModel.cs @@ -6,5 +6,5 @@ namespace Sample.Models; public partial class MockInputModel { - public readonly IReadOnlyList Prop1 { get; }; + public readonly IReadOnlyList Prop1 { get; } } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CanChangeModelPropertyWithChangedNamespace/MockInputModel.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CanChangeModelPropertyWithChangedNamespace/MockInputModel.cs index 561e17ffc7a..288f3532f69 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CanChangeModelPropertyWithChangedNamespace/MockInputModel.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CanChangeModelPropertyWithChangedNamespace/MockInputModel.cs @@ -6,5 +6,5 @@ namespace Sample.Models; public partial class MockInputModel { - public Foo Prop1 { get; }; + public Foo Prop1 { get; } } From fecf4f2300b88dc663f27dcb3f37bff78313a17b Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Tue, 9 Dec 2025 16:18:38 -0500 Subject: [PATCH 20/40] Bump version for typespec release 1.7.0 (#9168) --- ...rning-tsp-init-docs-2025-11-10-20-22-32.md | 7 ---- ...oding-comma-newline-2025-11-13-20-53-33.md | 8 ---- ...-csv-encoding-tests-2025-10-28-11-48-49.md | 7 ---- ...en-mutator-framework-2025-11-3-22-19-48.md | 8 ---- ...-unixtime-decorator-2025-12-09-16-54-20.md | 7 ---- ...tent-encoding-import-2025-12-5-18-32-55.md | 7 ---- ...code-duration-tests-2025-11-25-04-18-59.md | 7 ---- ...nal-docs-properties-2025-10-24-18-22-12.md | 8 ---- ...ature-help-test-slow-2025-10-14-2-25-10.md | 8 ---- ...-spector-source-url-2025-10-12-10-38-17.md | 9 ----- ...inter-async-callback-2025-10-6-12-33-19.md | 8 ---- .chronus/changes/main-2025-10-19-17-48-27.md | 15 ------- ...tor-circular-ref-fix-2025-10-21-6-44-36.md | 7 ---- ...iscriminator-support-2025-11-2-20-20-32.md | 7 ---- ...unions-response-doc-2025-10-10-16-34-57.md | 7 ---- ...unions-response-type-2025-10-10-16-34-2.md | 8 ---- .../remove-js-yaml-2025-10-17-18-13-50.md | 8 ---- .../source-model-node-2025-10-18-15-0-36.md | 7 ---- .../specs-addDocTest-2025-10-4-13-59-34.md | 7 ---- .../spector-new-case-2025-10-18-7-0-48.md | 7 ---- ...recognize-hyphen-param-2025-8-30-6-59-7.md | 8 ---- .../unused-as-hint-2025-10-13-17-12-1.md | 7 ---- ...pgrade-deps-nov-2025-2025-10-20-16-42-0.md | 40 ------------------- packages/asset-emitter/CHANGELOG.md | 7 ++++ packages/asset-emitter/package.json | 2 +- packages/bundler/CHANGELOG.md | 7 ++++ packages/bundler/package.json | 2 +- packages/compiler/CHANGELOG.md | 20 ++++++++++ packages/compiler/package.json | 2 +- packages/compiler/templates/scaffolding.json | 6 +-- packages/emitter-framework/CHANGELOG.md | 4 ++ packages/emitter-framework/package.json | 2 +- packages/eslint-plugin-typespec/CHANGELOG.md | 7 ++++ packages/eslint-plugin-typespec/package.json | 2 +- packages/events/CHANGELOG.md | 7 ++++ packages/events/package.json | 2 +- packages/html-program-viewer/CHANGELOG.md | 7 ++++ packages/html-program-viewer/package.json | 2 +- packages/http-canonicalization/CHANGELOG.md | 7 ++++ packages/http-canonicalization/package.json | 2 +- packages/http-client-js/CHANGELOG.md | 7 ++++ packages/http-client-js/package.json | 2 +- packages/http-client/CHANGELOG.md | 7 ++++ packages/http-client/package.json | 2 +- packages/http-server-csharp/CHANGELOG.md | 7 ++++ packages/http-server-csharp/package.json | 2 +- packages/http-server-js/CHANGELOG.md | 7 ++++ packages/http-server-js/package.json | 2 +- packages/http-specs/CHANGELOG.md | 18 +++++++++ packages/http-specs/package.json | 2 +- packages/http/CHANGELOG.md | 15 +++++++ packages/http/package.json | 2 +- packages/internal-build-utils/CHANGELOG.md | 7 ++++ packages/internal-build-utils/package.json | 2 +- packages/json-schema/CHANGELOG.md | 19 +++++++++ packages/json-schema/package.json | 2 +- packages/library-linter/CHANGELOG.md | 7 ++++ packages/library-linter/package.json | 2 +- packages/mutator-framework/CHANGELOG.md | 11 +++++ packages/mutator-framework/package.json | 2 +- packages/openapi/CHANGELOG.md | 7 ++++ packages/openapi/package.json | 2 +- packages/openapi3/CHANGELOG.md | 18 +++++++++ packages/openapi3/package.json | 2 +- packages/playground/CHANGELOG.md | 7 ++++ packages/playground/package.json | 2 +- .../prettier-plugin-typespec/CHANGELOG.md | 7 ++++ .../prettier-plugin-typespec/package.json | 2 +- packages/protobuf/CHANGELOG.md | 7 ++++ packages/protobuf/package.json | 2 +- packages/rest/CHANGELOG.md | 7 ++++ packages/rest/package.json | 2 +- packages/spec-api/CHANGELOG.md | 7 ++++ packages/spec-api/package.json | 2 +- packages/spec-coverage-sdk/CHANGELOG.md | 11 +++++ packages/spec-coverage-sdk/package.json | 2 +- packages/spector/CHANGELOG.md | 12 ++++++ packages/spector/package.json | 2 +- packages/sse/CHANGELOG.md | 7 ++++ packages/sse/package.json | 2 +- packages/standalone/CHANGELOG.md | 4 ++ packages/standalone/package.json | 2 +- packages/streams/CHANGELOG.md | 7 ++++ packages/streams/package.json | 2 +- packages/tmlanguage-generator/CHANGELOG.md | 7 ++++ packages/tmlanguage-generator/package.json | 2 +- packages/tspd/CHANGELOG.md | 7 ++++ packages/tspd/package.json | 2 +- packages/typespec-vs/CHANGELOG.md | 4 ++ packages/typespec-vs/package.json | 2 +- packages/typespec-vscode/CHANGELOG.md | 7 ++++ packages/typespec-vscode/package.json | 2 +- packages/versioning/CHANGELOG.md | 7 ++++ packages/versioning/package.json | 2 +- packages/xml/CHANGELOG.md | 7 ++++ packages/xml/package.json | 2 +- website/playground-versions.json | 1 + 97 files changed, 351 insertions(+), 251 deletions(-) delete mode 100644 .chronus/changes/add-security-warning-tsp-init-docs-2025-11-10-20-22-32.md delete mode 100644 .chronus/changes/array-encoding-comma-newline-2025-11-13-20-53-33.md delete mode 100644 .chronus/changes/copilot-add-csv-encoding-tests-2025-10-28-11-48-49.md delete mode 100644 .chronus/changes/fionabronwen-mutator-framework-2025-11-3-22-19-48.md delete mode 100644 .chronus/changes/fix-anyof-unixtime-decorator-2025-12-09-16-54-20.md delete mode 100644 .chronus/changes/fix-base64-content-encoding-import-2025-12-5-18-32-55.md delete mode 100644 .chronus/changes/fix-encode-duration-tests-2025-11-25-04-18-59.md delete mode 100644 .chronus/changes/fix-external-docs-properties-2025-10-24-18-22-12.md delete mode 100644 .chronus/changes/fix-signature-help-test-slow-2025-10-14-2-25-10.md delete mode 100644 .chronus/changes/fix-spector-source-url-2025-10-12-10-38-17.md delete mode 100644 .chronus/changes/linter-async-callback-2025-10-6-12-33-19.md delete mode 100644 .chronus/changes/main-2025-10-19-17-48-27.md delete mode 100644 .chronus/changes/mictaylor-json-schema-discriminator-circular-ref-fix-2025-10-21-6-44-36.md delete mode 100644 .chronus/changes/mictaylor-json-schema-open-discriminator-support-2025-11-2-20-20-32.md delete mode 100644 .chronus/changes/named-unions-response-doc-2025-10-10-16-34-57.md delete mode 100644 .chronus/changes/named-unions-response-type-2025-10-10-16-34-2.md delete mode 100644 .chronus/changes/remove-js-yaml-2025-10-17-18-13-50.md delete mode 100644 .chronus/changes/source-model-node-2025-10-18-15-0-36.md delete mode 100644 .chronus/changes/specs-addDocTest-2025-10-4-13-59-34.md delete mode 100644 .chronus/changes/spector-new-case-2025-10-18-7-0-48.md delete mode 100644 .chronus/changes/syntax-highlighting-not-correctly-recognize-hyphen-param-2025-8-30-6-59-7.md delete mode 100644 .chronus/changes/unused-as-hint-2025-10-13-17-12-1.md delete mode 100644 .chronus/changes/upgrade-deps-nov-2025-2025-10-20-16-42-0.md diff --git a/.chronus/changes/add-security-warning-tsp-init-docs-2025-11-10-20-22-32.md b/.chronus/changes/add-security-warning-tsp-init-docs-2025-11-10-20-22-32.md deleted file mode 100644 index ca7b265e5b7..00000000000 --- a/.chronus/changes/add-security-warning-tsp-init-docs-2025-11-10-20-22-32.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -changeKind: fix -packages: - - "@typespec/compiler" ---- - -Add security warning to tsp init CLI documentation for external templates (#8916) diff --git a/.chronus/changes/array-encoding-comma-newline-2025-11-13-20-53-33.md b/.chronus/changes/array-encoding-comma-newline-2025-11-13-20-53-33.md deleted file mode 100644 index 2f6c1a3c6c7..00000000000 --- a/.chronus/changes/array-encoding-comma-newline-2025-11-13-20-53-33.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -changeKind: feature -packages: - - "@typespec/compiler" - - "@typespec/openapi3" ---- - -Add `commaDelimited` and `newlineDelimited` values to `ArrayEncoding` enum for serializing arrays with comma and newline delimiters diff --git a/.chronus/changes/copilot-add-csv-encoding-tests-2025-10-28-11-48-49.md b/.chronus/changes/copilot-add-csv-encoding-tests-2025-10-28-11-48-49.md deleted file mode 100644 index d2a1d3706c7..00000000000 --- a/.chronus/changes/copilot-add-csv-encoding-tests-2025-10-28-11-48-49.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -changeKind: feature -packages: - - "@typespec/http-specs" ---- - -Add tests for array encode. \ No newline at end of file diff --git a/.chronus/changes/fionabronwen-mutator-framework-2025-11-3-22-19-48.md b/.chronus/changes/fionabronwen-mutator-framework-2025-11-3-22-19-48.md deleted file mode 100644 index 5b28cf330b5..00000000000 --- a/.chronus/changes/fionabronwen-mutator-framework-2025-11-3-22-19-48.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking -changeKind: feature -packages: - - "@typespec/mutator-framework" ---- - -Add `EnumMutation` and `EnumMemberMutation` to the Mutator Framework diff --git a/.chronus/changes/fix-anyof-unixtime-decorator-2025-12-09-16-54-20.md b/.chronus/changes/fix-anyof-unixtime-decorator-2025-12-09-16-54-20.md deleted file mode 100644 index c7cc8c897b2..00000000000 --- a/.chronus/changes/fix-anyof-unixtime-decorator-2025-12-09-16-54-20.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -changeKind: fix -packages: - - "@typespec/openapi3" ---- - -Import OpenAPI schemas with anyOf/oneOf containing unixtime format correctly emits `@encode(DateTimeKnownEncoding.unixTimestamp, integer)` decorator for nullable utcDateTime properties diff --git a/.chronus/changes/fix-base64-content-encoding-import-2025-12-5-18-32-55.md b/.chronus/changes/fix-base64-content-encoding-import-2025-12-5-18-32-55.md deleted file mode 100644 index 7a9fea578ae..00000000000 --- a/.chronus/changes/fix-base64-content-encoding-import-2025-12-5-18-32-55.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -changeKind: fix -packages: - - "@typespec/openapi3" ---- - -Import OpenAPI 3.1/3.2 schemas with contentEncoding: base64 as bytes type with `@encode("base64", string)` decorator diff --git a/.chronus/changes/fix-encode-duration-tests-2025-11-25-04-18-59.md b/.chronus/changes/fix-encode-duration-tests-2025-11-25-04-18-59.md deleted file mode 100644 index 16a7b59f680..00000000000 --- a/.chronus/changes/fix-encode-duration-tests-2025-11-25-04-18-59.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -changeKind: fix -packages: - - "@typespec/http-specs" ---- - -Fix EncodeDuration tests with larger unit durations being too strict by making query parameter expectations match input types as numbers instead of strings diff --git a/.chronus/changes/fix-external-docs-properties-2025-10-24-18-22-12.md b/.chronus/changes/fix-external-docs-properties-2025-10-24-18-22-12.md deleted file mode 100644 index f1e5a51a68d..00000000000 --- a/.chronus/changes/fix-external-docs-properties-2025-10-24-18-22-12.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking -changeKind: fix -packages: - - "@typespec/openapi3" ---- - -Respect `@externalDocs` on properties diff --git a/.chronus/changes/fix-signature-help-test-slow-2025-10-14-2-25-10.md b/.chronus/changes/fix-signature-help-test-slow-2025-10-14-2-25-10.md deleted file mode 100644 index 5a703a4f8df..00000000000 --- a/.chronus/changes/fix-signature-help-test-slow-2025-10-14-2-25-10.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking -changeKind: internal -packages: - - "@typespec/compiler" ---- - -Fix signature help test super slow diff --git a/.chronus/changes/fix-spector-source-url-2025-10-12-10-38-17.md b/.chronus/changes/fix-spector-source-url-2025-10-12-10-38-17.md deleted file mode 100644 index df937acedcd..00000000000 --- a/.chronus/changes/fix-spector-source-url-2025-10-12-10-38-17.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -changeKind: fix -packages: - - "@typespec/http-specs" - - "@typespec/spec-coverage-sdk" - - "@typespec/spector" ---- - -Add new `sourceUrl` handling for the go to source navigation \ No newline at end of file diff --git a/.chronus/changes/linter-async-callback-2025-10-6-12-33-19.md b/.chronus/changes/linter-async-callback-2025-10-6-12-33-19.md deleted file mode 100644 index b4aa8b1f17a..00000000000 --- a/.chronus/changes/linter-async-callback-2025-10-6-12-33-19.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -changeKind: feature -packages: - - "@typespec/compiler" ---- - -- Add 'exit' final event for linter rules -- Support 'async' in linter definition and async function as callback for 'exit' event. diff --git a/.chronus/changes/main-2025-10-19-17-48-27.md b/.chronus/changes/main-2025-10-19-17-48-27.md deleted file mode 100644 index 42ce7ad3260..00000000000 --- a/.chronus/changes/main-2025-10-19-17-48-27.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -changeKind: feature -packages: - - "@typespec/json-schema" ---- - -Add discriminator support and polymorphic models strategy option - -- Automatically injects discriminator property into base models with `@discriminator` decorator -- Marks discriminator property as required in generated schemas -- New `polymorphic-models-strategy` emitter option with three strategies: - - `ignore`: Emit as regular object schema (default) - - `oneOf`: Emit oneOf schema for closed discriminated unions - - `anyOf`: Emit anyOf schema for open discriminated unions -- Includes discriminator.mapping in oneOf/anyOf schemas for improved validation diff --git a/.chronus/changes/mictaylor-json-schema-discriminator-circular-ref-fix-2025-10-21-6-44-36.md b/.chronus/changes/mictaylor-json-schema-discriminator-circular-ref-fix-2025-10-21-6-44-36.md deleted file mode 100644 index 73255d9578e..00000000000 --- a/.chronus/changes/mictaylor-json-schema-discriminator-circular-ref-fix-2025-10-21-6-44-36.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -changeKind: internal -packages: - - "@typespec/json-schema" ---- - -avoid circular references in discriminated unions with polymorphic-models-strategy \ No newline at end of file diff --git a/.chronus/changes/mictaylor-json-schema-open-discriminator-support-2025-11-2-20-20-32.md b/.chronus/changes/mictaylor-json-schema-open-discriminator-support-2025-11-2-20-20-32.md deleted file mode 100644 index 9b482e190ad..00000000000 --- a/.chronus/changes/mictaylor-json-schema-open-discriminator-support-2025-11-2-20-20-32.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -changeKind: internal -packages: - - "@typespec/json-schema" ---- - -add support for open discriminators diff --git a/.chronus/changes/named-unions-response-doc-2025-10-10-16-34-57.md b/.chronus/changes/named-unions-response-doc-2025-10-10-16-34-57.md deleted file mode 100644 index 95efc2352e1..00000000000 --- a/.chronus/changes/named-unions-response-doc-2025-10-10-16-34-57.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -changeKind: feature -packages: - - "@typespec/http" ---- - -support documentation on union variants for response descriptions diff --git a/.chronus/changes/named-unions-response-type-2025-10-10-16-34-2.md b/.chronus/changes/named-unions-response-type-2025-10-10-16-34-2.md deleted file mode 100644 index 29570e50e91..00000000000 --- a/.chronus/changes/named-unions-response-type-2025-10-10-16-34-2.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -changeKind: fix -packages: - - "@typespec/http" - - "@typespec/openapi3" ---- - -Support nested unions in operation return types diff --git a/.chronus/changes/remove-js-yaml-2025-10-17-18-13-50.md b/.chronus/changes/remove-js-yaml-2025-10-17-18-13-50.md deleted file mode 100644 index 2fc2e9ba41b..00000000000 --- a/.chronus/changes/remove-js-yaml-2025-10-17-18-13-50.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking -changeKind: fix -packages: - - "@typespec/spector" ---- - -Switch `js-yaml` to `yaml` library diff --git a/.chronus/changes/source-model-node-2025-10-18-15-0-36.md b/.chronus/changes/source-model-node-2025-10-18-15-0-36.md deleted file mode 100644 index 35cc9a9177c..00000000000 --- a/.chronus/changes/source-model-node-2025-10-18-15-0-36.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -changeKind: feature -packages: - - "@typespec/compiler" ---- - -[API] Add `node` to `SourceModel` type \ No newline at end of file diff --git a/.chronus/changes/specs-addDocTest-2025-10-4-13-59-34.md b/.chronus/changes/specs-addDocTest-2025-10-4-13-59-34.md deleted file mode 100644 index 229d5793b93..00000000000 --- a/.chronus/changes/specs-addDocTest-2025-10-4-13-59-34.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -changeKind: feature -packages: - - "@typespec/http-specs" ---- - -add test for documentation generation \ No newline at end of file diff --git a/.chronus/changes/spector-new-case-2025-10-18-7-0-48.md b/.chronus/changes/spector-new-case-2025-10-18-7-0-48.md deleted file mode 100644 index 50498f86a84..00000000000 --- a/.chronus/changes/spector-new-case-2025-10-18-7-0-48.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -changeKind: feature -packages: - - "@typespec/http-specs" ---- - -Add test case for special words about model property name \ No newline at end of file diff --git a/.chronus/changes/syntax-highlighting-not-correctly-recognize-hyphen-param-2025-8-30-6-59-7.md b/.chronus/changes/syntax-highlighting-not-correctly-recognize-hyphen-param-2025-8-30-6-59-7.md deleted file mode 100644 index 6bb5e75d6ec..00000000000 --- a/.chronus/changes/syntax-highlighting-not-correctly-recognize-hyphen-param-2025-8-30-6-59-7.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking -changeKind: feature -packages: - - "@typespec/compiler" ---- - -Add support for escaping param like tags(`@param`, `@prop`, etc.) identifier with backtick in doc comments to allow special characters diff --git a/.chronus/changes/unused-as-hint-2025-10-13-17-12-1.md b/.chronus/changes/unused-as-hint-2025-10-13-17-12-1.md deleted file mode 100644 index f53472dfb3d..00000000000 --- a/.chronus/changes/unused-as-hint-2025-10-13-17-12-1.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -changeKind: fix -packages: - - "@typespec/compiler" ---- - -UnusedUsing Diagnostics are reported as warning instead of hint when there are linters defined in tspconfig.yaml diff --git a/.chronus/changes/upgrade-deps-nov-2025-2025-10-20-16-42-0.md b/.chronus/changes/upgrade-deps-nov-2025-2025-10-20-16-42-0.md deleted file mode 100644 index 7cf26ce1ae4..00000000000 --- a/.chronus/changes/upgrade-deps-nov-2025-2025-10-20-16-42-0.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking -changeKind: dependencies -packages: - - "@typespec/asset-emitter" - - "@typespec/bundler" - - "@typespec/compiler" - - "@typespec/eslint-plugin" - - "@typespec/events" - - "@typespec/html-program-viewer" - - "@typespec/http-specs" - - "@typespec/http" - - "@typespec/internal-build-utils" - - "@typespec/json-schema" - - "@typespec/library-linter" - - "@typespec/openapi" - - "@typespec/openapi3" - - "@typespec/playground" - - "@typespec/protobuf" - - "@typespec/rest" - - "@typespec/spec-api" - - "@typespec/spec-coverage-sdk" - - "@typespec/spector" - - "@typespec/sse" - - "@typespec/streams" - - tmlanguage-generator - - "@typespec/tspd" - - typespec-vscode - - "@typespec/versioning" - - "@typespec/xml" - - "@typespec/http-canonicalization" - - "@typespec/http-client-js" - - "@typespec/http-client" - - "@typespec/http-server-csharp" - - "@typespec/http-server-js" - - "@typespec/mutator-framework" - - "@typespec/prettier-plugin-typespec" ---- - -Upgrade dependencies diff --git a/packages/asset-emitter/CHANGELOG.md b/packages/asset-emitter/CHANGELOG.md index 9abff680b7e..b6c86653f28 100644 --- a/packages/asset-emitter/CHANGELOG.md +++ b/packages/asset-emitter/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog - @typespec/asset-emitter +## 0.77.0 + +### Bump dependencies + +- [#9046](https://github.com/microsoft/typespec/pull/9046) Upgrade dependencies + + ## 0.76.0 ### Bump dependencies diff --git a/packages/asset-emitter/package.json b/packages/asset-emitter/package.json index c928d460fa9..bb6116615a5 100644 --- a/packages/asset-emitter/package.json +++ b/packages/asset-emitter/package.json @@ -1,6 +1,6 @@ { "name": "@typespec/asset-emitter", - "version": "0.76.0", + "version": "0.77.0", "author": "Microsoft Corporation", "description": "TypeSpec Asset Emitter, this is to be replaced by the new emitter framework", "homepage": "https://typespec.io", diff --git a/packages/bundler/CHANGELOG.md b/packages/bundler/CHANGELOG.md index ebb1621c840..bb02ab580b7 100644 --- a/packages/bundler/CHANGELOG.md +++ b/packages/bundler/CHANGELOG.md @@ -1,5 +1,12 @@ # Change Log - @typespec/bundler +## 0.4.6 + +### Bump dependencies + +- [#9046](https://github.com/microsoft/typespec/pull/9046) Upgrade dependencies + + ## 0.4.5 ### Bump dependencies diff --git a/packages/bundler/package.json b/packages/bundler/package.json index 9df27e4475d..b9512871172 100644 --- a/packages/bundler/package.json +++ b/packages/bundler/package.json @@ -1,6 +1,6 @@ { "name": "@typespec/bundler", - "version": "0.4.5", + "version": "0.4.6", "author": "Microsoft Corporation", "description": "Package to bundle a TypeSpec library.", "homepage": "https://typespec.io", diff --git a/packages/compiler/CHANGELOG.md b/packages/compiler/CHANGELOG.md index c012937c02d..d06d3d54bba 100644 --- a/packages/compiler/CHANGELOG.md +++ b/packages/compiler/CHANGELOG.md @@ -1,5 +1,25 @@ # Change Log - @typespec/compiler +## 1.7.0 + +### Features + +- [#9002](https://github.com/microsoft/typespec/pull/9002) Add `commaDelimited` and `newlineDelimited` values to `ArrayEncoding` enum for serializing arrays with comma and newline delimiters +- [#8942](https://github.com/microsoft/typespec/pull/8942) - Add 'exit' final event for linter rules + - Support 'async' in linter definition and async function as callback for 'exit' event. +- [#9024](https://github.com/microsoft/typespec/pull/9024) [API] Add `node` to `SourceModel` type +- [#8619](https://github.com/microsoft/typespec/pull/8619) Add support for escaping param like tags(`@param`, `@prop`, etc.) identifier with backtick in doc comments to allow special characters + +### Bump dependencies + +- [#9046](https://github.com/microsoft/typespec/pull/9046) Upgrade dependencies + +### Bug Fixes + +- [#8917](https://github.com/microsoft/typespec/pull/8917) Add security warning to tsp init CLI documentation for external templates (#8916) +- [#8997](https://github.com/microsoft/typespec/pull/8997) UnusedUsing Diagnostics are reported as warning instead of hint when there are linters defined in tspconfig.yaml + + ## 1.6.0 ### Features diff --git a/packages/compiler/package.json b/packages/compiler/package.json index 93c0b36d9be..3932fffaef3 100644 --- a/packages/compiler/package.json +++ b/packages/compiler/package.json @@ -1,6 +1,6 @@ { "name": "@typespec/compiler", - "version": "1.6.0", + "version": "1.7.0", "description": "TypeSpec Compiler Preview", "author": "Microsoft Corporation", "license": "MIT", diff --git a/packages/compiler/templates/scaffolding.json b/packages/compiler/templates/scaffolding.json index 77f752854d4..66b69f96d69 100644 --- a/packages/compiler/templates/scaffolding.json +++ b/packages/compiler/templates/scaffolding.json @@ -2,7 +2,7 @@ "rest": { "title": "Generic REST API", "description": "Create a project representing a generic REST API service.", - "compilerVersion": "1.6.0", + "compilerVersion": "1.7.0", "libraries": [ "@typespec/http", "@typespec/rest", @@ -70,7 +70,7 @@ "target": "library", "title": "TypeSpec library", "description": "Build your own TypeSpec library with custom types, decorators or linters.", - "compilerVersion": "1.6.0", + "compilerVersion": "1.7.0", "libraries": [], "files": [ { @@ -147,7 +147,7 @@ "target": "library", "title": "TypeSpec emitter", "description": "Create a new package that emits artifacts from TypeSpec.", - "compilerVersion": "1.6.0", + "compilerVersion": "1.7.0", "libraries": [], "files": [ { diff --git a/packages/emitter-framework/CHANGELOG.md b/packages/emitter-framework/CHANGELOG.md index 0743748ac43..63d99036145 100644 --- a/packages/emitter-framework/CHANGELOG.md +++ b/packages/emitter-framework/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog - @typespec/emitter-framework +## 0.14.0 + +No changes, version bump only. + ## 0.13.0 ### Features diff --git a/packages/emitter-framework/package.json b/packages/emitter-framework/package.json index 83311704045..3d2caecb5d7 100644 --- a/packages/emitter-framework/package.json +++ b/packages/emitter-framework/package.json @@ -1,6 +1,6 @@ { "name": "@typespec/emitter-framework", - "version": "0.13.0", + "version": "0.14.0", "type": "module", "main": "dist/index.js", "repository": { diff --git a/packages/eslint-plugin-typespec/CHANGELOG.md b/packages/eslint-plugin-typespec/CHANGELOG.md index 3d0b5f8b612..346d40474e2 100644 --- a/packages/eslint-plugin-typespec/CHANGELOG.md +++ b/packages/eslint-plugin-typespec/CHANGELOG.md @@ -1,5 +1,12 @@ # Change Log - @typespec/eslint-plugin +## 0.77.0 + +### Bump dependencies + +- [#9046](https://github.com/microsoft/typespec/pull/9046) Upgrade dependencies + + ## 0.76.0 ### Bump dependencies diff --git a/packages/eslint-plugin-typespec/package.json b/packages/eslint-plugin-typespec/package.json index 9c45b810891..80aa8a1a0a8 100644 --- a/packages/eslint-plugin-typespec/package.json +++ b/packages/eslint-plugin-typespec/package.json @@ -1,6 +1,6 @@ { "name": "@typespec/eslint-plugin", - "version": "0.76.0", + "version": "0.77.0", "author": "Microsoft Corporation", "description": "Eslint plugin providing set of rules to be used in the JS/TS code of TypeSpec libraries", "homepage": "https://typespec.io", diff --git a/packages/events/CHANGELOG.md b/packages/events/CHANGELOG.md index 550c463673a..80285d3449b 100644 --- a/packages/events/CHANGELOG.md +++ b/packages/events/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog - @typespec/events +## 0.77.0 + +### Bump dependencies + +- [#9046](https://github.com/microsoft/typespec/pull/9046) Upgrade dependencies + + ## 0.76.0 ### Bump dependencies diff --git a/packages/events/package.json b/packages/events/package.json index 19f34577221..bb4dbf44a8d 100644 --- a/packages/events/package.json +++ b/packages/events/package.json @@ -1,6 +1,6 @@ { "name": "@typespec/events", - "version": "0.76.0", + "version": "0.77.0", "author": "Microsoft Corporation", "description": "TypeSpec library providing events bindings", "homepage": "https://typespec.io", diff --git a/packages/html-program-viewer/CHANGELOG.md b/packages/html-program-viewer/CHANGELOG.md index 8ec3845583c..23f9b710fd6 100644 --- a/packages/html-program-viewer/CHANGELOG.md +++ b/packages/html-program-viewer/CHANGELOG.md @@ -1,5 +1,12 @@ # Change Log - @typespec/html-program-viewer +## 0.77.0 + +### Bump dependencies + +- [#9046](https://github.com/microsoft/typespec/pull/9046) Upgrade dependencies + + ## 0.76.0 ### Bump dependencies diff --git a/packages/html-program-viewer/package.json b/packages/html-program-viewer/package.json index a89cba0478a..c8d8f2db103 100644 --- a/packages/html-program-viewer/package.json +++ b/packages/html-program-viewer/package.json @@ -1,6 +1,6 @@ { "name": "@typespec/html-program-viewer", - "version": "0.76.0", + "version": "0.77.0", "author": "Microsoft Corporation", "description": "TypeSpec library for emitting an html view of the program.", "homepage": "https://typespec.io", diff --git a/packages/http-canonicalization/CHANGELOG.md b/packages/http-canonicalization/CHANGELOG.md index e86e0848d9a..da32270abbd 100644 --- a/packages/http-canonicalization/CHANGELOG.md +++ b/packages/http-canonicalization/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog - @typespec/http-canonicalization +## 0.14.0 + +### Bump dependencies + +- [#9046](https://github.com/microsoft/typespec/pull/9046) Upgrade dependencies + + ## 0.13.0 diff --git a/packages/http-canonicalization/package.json b/packages/http-canonicalization/package.json index 76e2ebb55a8..c0c5a37a0a4 100644 --- a/packages/http-canonicalization/package.json +++ b/packages/http-canonicalization/package.json @@ -1,6 +1,6 @@ { "name": "@typespec/http-canonicalization", - "version": "0.13.0", + "version": "0.14.0", "type": "module", "main": "dist/src/index.js", "repository": { diff --git a/packages/http-client-js/CHANGELOG.md b/packages/http-client-js/CHANGELOG.md index 44822463724..9ff4c5053f9 100644 --- a/packages/http-client-js/CHANGELOG.md +++ b/packages/http-client-js/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog - @typespec/http-client-js +## 0.12.0 + +### Bump dependencies + +- [#9046](https://github.com/microsoft/typespec/pull/9046) Upgrade dependencies + + ## 0.11.0 ### Bump dependencies diff --git a/packages/http-client-js/package.json b/packages/http-client-js/package.json index e1027660743..4c544e9eafe 100644 --- a/packages/http-client-js/package.json +++ b/packages/http-client-js/package.json @@ -1,6 +1,6 @@ { "name": "@typespec/http-client-js", - "version": "0.11.0", + "version": "0.12.0", "type": "module", "homepage": "https://typespec.io", "readme": "https://github.com/microsoft/typespec/blob/main/packages/http-client-js/README.md", diff --git a/packages/http-client/CHANGELOG.md b/packages/http-client/CHANGELOG.md index 88d8af82a0b..c8f59e9f522 100644 --- a/packages/http-client/CHANGELOG.md +++ b/packages/http-client/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog - @typespec/http-client +## 0.13.0 + +### Bump dependencies + +- [#9046](https://github.com/microsoft/typespec/pull/9046) Upgrade dependencies + + ## 0.12.0 ### Bump dependencies diff --git a/packages/http-client/package.json b/packages/http-client/package.json index a1328161190..f7491d2b854 100644 --- a/packages/http-client/package.json +++ b/packages/http-client/package.json @@ -1,6 +1,6 @@ { "name": "@typespec/http-client", - "version": "0.12.0", + "version": "0.13.0", "type": "module", "main": "dist/src/index.js", "license": "MIT", diff --git a/packages/http-server-csharp/CHANGELOG.md b/packages/http-server-csharp/CHANGELOG.md index 03d2b087d89..f3a9356de39 100644 --- a/packages/http-server-csharp/CHANGELOG.md +++ b/packages/http-server-csharp/CHANGELOG.md @@ -1,5 +1,12 @@ # Change Log - @typespec/http-server-csharp +## 0.58.0-alpha.23 + +### Bump dependencies + +- [#9046](https://github.com/microsoft/typespec/pull/9046) Upgrade dependencies + + ## 0.58.0-alpha.22 ### Bump dependencies diff --git a/packages/http-server-csharp/package.json b/packages/http-server-csharp/package.json index 01264ce5beb..bd82511af26 100644 --- a/packages/http-server-csharp/package.json +++ b/packages/http-server-csharp/package.json @@ -1,6 +1,6 @@ { "name": "@typespec/http-server-csharp", - "version": "0.58.0-alpha.22", + "version": "0.58.0-alpha.23", "author": "Microsoft Corporation", "description": "TypeSpec service code generator for c-sharp", "homepage": "https://typespec.io", diff --git a/packages/http-server-js/CHANGELOG.md b/packages/http-server-js/CHANGELOG.md index b0b781d9c02..dd4639adec9 100644 --- a/packages/http-server-js/CHANGELOG.md +++ b/packages/http-server-js/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog - @typespec/http-server-js +## 0.58.0-alpha.22 + +### Bump dependencies + +- [#9046](https://github.com/microsoft/typespec/pull/9046) Upgrade dependencies + + ## 0.58.0-alpha.21 ### Bump dependencies diff --git a/packages/http-server-js/package.json b/packages/http-server-js/package.json index bd3d41ed0b4..54bba9cb1cc 100644 --- a/packages/http-server-js/package.json +++ b/packages/http-server-js/package.json @@ -1,6 +1,6 @@ { "name": "@typespec/http-server-js", - "version": "0.58.0-alpha.21", + "version": "0.58.0-alpha.22", "author": "Microsoft Corporation", "description": "TypeSpec HTTP server code generator for JavaScript", "homepage": "https://github.com/microsoft/typespec", diff --git a/packages/http-specs/CHANGELOG.md b/packages/http-specs/CHANGELOG.md index b722a2542e4..d89ab258471 100644 --- a/packages/http-specs/CHANGELOG.md +++ b/packages/http-specs/CHANGELOG.md @@ -1,5 +1,23 @@ # @typespec/http-specs +## 0.1.0-alpha.29 + +### Features + +- [#9106](https://github.com/microsoft/typespec/pull/9106) Add tests for array encode. +- [#8929](https://github.com/microsoft/typespec/pull/8929) add test for documentation generation +- [#9019](https://github.com/microsoft/typespec/pull/9019) Add test case for special words about model property name + +### Bump dependencies + +- [#9046](https://github.com/microsoft/typespec/pull/9046) Upgrade dependencies + +### Bug Fixes + +- [#9039](https://github.com/microsoft/typespec/pull/9039) Fix EncodeDuration tests with larger unit durations being too strict by making query parameter expectations match input types as numbers instead of strings +- [#8985](https://github.com/microsoft/typespec/pull/8985) Add new `sourceUrl` handling for the go to source navigation + + ## 0.1.0-alpha.28 ### Features diff --git a/packages/http-specs/package.json b/packages/http-specs/package.json index 4bd818804e5..764d09b0be3 100644 --- a/packages/http-specs/package.json +++ b/packages/http-specs/package.json @@ -1,7 +1,7 @@ { "name": "@typespec/http-specs", "displayName": "Http Specs", - "version": "0.1.0-alpha.28", + "version": "0.1.0-alpha.29", "description": "Spec scenarios and mock apis", "main": "dist/index.js", "type": "module", diff --git a/packages/http/CHANGELOG.md b/packages/http/CHANGELOG.md index e51565c5359..4800e1710d7 100644 --- a/packages/http/CHANGELOG.md +++ b/packages/http/CHANGELOG.md @@ -1,5 +1,20 @@ # Change Log - @typespec/http +## 1.7.0 + +### Features + +- [#8962](https://github.com/microsoft/typespec/pull/8962) support documentation on union variants for response descriptions + +### Bump dependencies + +- [#9046](https://github.com/microsoft/typespec/pull/9046) Upgrade dependencies + +### Bug Fixes + +- [#8961](https://github.com/microsoft/typespec/pull/8961) Support nested unions in operation return types + + ## 1.6.0 ### Bump dependencies diff --git a/packages/http/package.json b/packages/http/package.json index edd9605b977..048f4e0170a 100644 --- a/packages/http/package.json +++ b/packages/http/package.json @@ -1,6 +1,6 @@ { "name": "@typespec/http", - "version": "1.6.0", + "version": "1.7.0", "author": "Microsoft Corporation", "description": "TypeSpec HTTP protocol binding", "homepage": "https://github.com/microsoft/typespec", diff --git a/packages/internal-build-utils/CHANGELOG.md b/packages/internal-build-utils/CHANGELOG.md index 04b74a5ddde..c8243de5acf 100644 --- a/packages/internal-build-utils/CHANGELOG.md +++ b/packages/internal-build-utils/CHANGELOG.md @@ -1,5 +1,12 @@ # Change Log - @typespec/internal-build-utils +## 0.77.0 + +### Bump dependencies + +- [#9046](https://github.com/microsoft/typespec/pull/9046) Upgrade dependencies + + ## 0.76.0 ### Bump dependencies diff --git a/packages/internal-build-utils/package.json b/packages/internal-build-utils/package.json index 9f9f05fe682..a0800d9ca4b 100644 --- a/packages/internal-build-utils/package.json +++ b/packages/internal-build-utils/package.json @@ -1,6 +1,6 @@ { "name": "@typespec/internal-build-utils", - "version": "0.76.0", + "version": "0.77.0", "author": "Microsoft Corporation", "description": "Internal library to TypeSpec providing helpers to build.", "homepage": "https://typespec.io", diff --git a/packages/json-schema/CHANGELOG.md b/packages/json-schema/CHANGELOG.md index 7a992746202..0128ff2400e 100644 --- a/packages/json-schema/CHANGELOG.md +++ b/packages/json-schema/CHANGELOG.md @@ -1,5 +1,24 @@ # Change Log - @typespec/json-schema +## 1.7.0 + +### Features + +- [#9038](https://github.com/microsoft/typespec/pull/9038) Add discriminator support and polymorphic models strategy option + + - Automatically injects discriminator property into base models with `@discriminator` decorator + - Marks discriminator property as required in generated schemas + - New `polymorphic-models-strategy` emitter option with three strategies: + - `ignore`: Emit as regular object schema (default) + - `oneOf`: Emit oneOf schema for closed discriminated unions + - `anyOf`: Emit anyOf schema for open discriminated unions + - Includes discriminator.mapping in oneOf/anyOf schemas for improved validation + +### Bump dependencies + +- [#9046](https://github.com/microsoft/typespec/pull/9046) Upgrade dependencies + + ## 1.6.0 ### Bump dependencies diff --git a/packages/json-schema/package.json b/packages/json-schema/package.json index e95a651b53a..3adb9625717 100644 --- a/packages/json-schema/package.json +++ b/packages/json-schema/package.json @@ -1,6 +1,6 @@ { "name": "@typespec/json-schema", - "version": "1.6.0", + "version": "1.7.0", "author": "Microsoft Corporation", "description": "TypeSpec library for emitting TypeSpec to JSON Schema and converting JSON Schema to TypeSpec", "homepage": "https://github.com/microsoft/typespec", diff --git a/packages/library-linter/CHANGELOG.md b/packages/library-linter/CHANGELOG.md index 251033aca1d..83974cab7da 100644 --- a/packages/library-linter/CHANGELOG.md +++ b/packages/library-linter/CHANGELOG.md @@ -1,5 +1,12 @@ # Change Log - @typespec/library-linter +## 0.77.0 + +### Bump dependencies + +- [#9046](https://github.com/microsoft/typespec/pull/9046) Upgrade dependencies + + ## 0.76.0 ### Bump dependencies diff --git a/packages/library-linter/package.json b/packages/library-linter/package.json index a2036c2ea13..68fa23d757c 100644 --- a/packages/library-linter/package.json +++ b/packages/library-linter/package.json @@ -1,6 +1,6 @@ { "name": "@typespec/library-linter", - "version": "0.76.0", + "version": "0.77.0", "author": "Microsoft Corporation", "description": "TypeSpec library for linting another library.", "homepage": "https://typespec.io", diff --git a/packages/mutator-framework/CHANGELOG.md b/packages/mutator-framework/CHANGELOG.md index 9703caf7b00..e664f4cd020 100644 --- a/packages/mutator-framework/CHANGELOG.md +++ b/packages/mutator-framework/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog - @typespec/mutator-framework +## 0.14.0 + +### Features + +- [#9133](https://github.com/microsoft/typespec/pull/9133) Add `EnumMutation` and `EnumMemberMutation` to the Mutator Framework + +### Bump dependencies + +- [#9046](https://github.com/microsoft/typespec/pull/9046) Upgrade dependencies + + ## 0.13.0 ### Features diff --git a/packages/mutator-framework/package.json b/packages/mutator-framework/package.json index c74a83cce68..a80794a80d7 100644 --- a/packages/mutator-framework/package.json +++ b/packages/mutator-framework/package.json @@ -1,6 +1,6 @@ { "name": "@typespec/mutator-framework", - "version": "0.13.0", + "version": "0.14.0", "type": "module", "main": "dist/src/index.js", "repository": { diff --git a/packages/openapi/CHANGELOG.md b/packages/openapi/CHANGELOG.md index b7989d6207f..d2ae28e4e16 100644 --- a/packages/openapi/CHANGELOG.md +++ b/packages/openapi/CHANGELOG.md @@ -1,5 +1,12 @@ # Change Log - @typespec/openapi +## 1.7.0 + +### Bump dependencies + +- [#9046](https://github.com/microsoft/typespec/pull/9046) Upgrade dependencies + + ## 1.6.0 ### Bump dependencies diff --git a/packages/openapi/package.json b/packages/openapi/package.json index ec4a1ca7373..89a2ec1699d 100644 --- a/packages/openapi/package.json +++ b/packages/openapi/package.json @@ -1,6 +1,6 @@ { "name": "@typespec/openapi", - "version": "1.6.0", + "version": "1.7.0", "author": "Microsoft Corporation", "description": "TypeSpec library providing OpenAPI concepts", "homepage": "https://typespec.io", diff --git a/packages/openapi3/CHANGELOG.md b/packages/openapi3/CHANGELOG.md index 244774de7e5..ea02ddd8a37 100644 --- a/packages/openapi3/CHANGELOG.md +++ b/packages/openapi3/CHANGELOG.md @@ -1,5 +1,23 @@ # Change Log - @typespec/openapi3 +## 1.7.0 + +### Features + +- [#9002](https://github.com/microsoft/typespec/pull/9002) Add `commaDelimited` and `newlineDelimited` values to `ArrayEncoding` enum for serializing arrays with comma and newline delimiters + +### Bump dependencies + +- [#9046](https://github.com/microsoft/typespec/pull/9046) Upgrade dependencies + +### Bug Fixes + +- [#9164](https://github.com/microsoft/typespec/pull/9164) Import OpenAPI schemas with anyOf/oneOf containing unixtime format correctly emits `@encode(DateTimeKnownEncoding.unixTimestamp, integer)` decorator for nullable utcDateTime properties +- [#9151](https://github.com/microsoft/typespec/pull/9151) Import OpenAPI 3.1/3.2 schemas with contentEncoding: base64 as bytes type with `@encode("base64", string)` decorator +- [#9076](https://github.com/microsoft/typespec/pull/9076) Respect `@externalDocs` on properties +- [#8961](https://github.com/microsoft/typespec/pull/8961) Support nested unions in operation return types + + ## 1.6.0 ### Features diff --git a/packages/openapi3/package.json b/packages/openapi3/package.json index 666840dbcd6..808a34e02d1 100644 --- a/packages/openapi3/package.json +++ b/packages/openapi3/package.json @@ -1,6 +1,6 @@ { "name": "@typespec/openapi3", - "version": "1.6.0", + "version": "1.7.0", "author": "Microsoft Corporation", "description": "TypeSpec library for emitting OpenAPI 3.0 and OpenAPI 3.1 from the TypeSpec REST protocol binding and converting OpenAPI3 to TypeSpec", "homepage": "https://typespec.io", diff --git a/packages/playground/CHANGELOG.md b/packages/playground/CHANGELOG.md index a952229494b..0096b5da0a8 100644 --- a/packages/playground/CHANGELOG.md +++ b/packages/playground/CHANGELOG.md @@ -1,5 +1,12 @@ # Change Log - @typespec/playground +## 0.11.3 + +### Bump dependencies + +- [#9046](https://github.com/microsoft/typespec/pull/9046) Upgrade dependencies + + ## 0.11.2 ### Bump dependencies diff --git a/packages/playground/package.json b/packages/playground/package.json index 7eaccd2478c..90b61bf5f72 100644 --- a/packages/playground/package.json +++ b/packages/playground/package.json @@ -1,6 +1,6 @@ { "name": "@typespec/playground", - "version": "0.11.2", + "version": "0.11.3", "author": "Microsoft Corporation", "description": "TypeSpec playground UI components.", "homepage": "https://typespec.io", diff --git a/packages/prettier-plugin-typespec/CHANGELOG.md b/packages/prettier-plugin-typespec/CHANGELOG.md index ca3052569ff..3375cca3c88 100644 --- a/packages/prettier-plugin-typespec/CHANGELOG.md +++ b/packages/prettier-plugin-typespec/CHANGELOG.md @@ -1,5 +1,12 @@ # Change Log - @typespec/prettier-plugin-typespec +## 1.7.0 + +### Bump dependencies + +- [#9046](https://github.com/microsoft/typespec/pull/9046) Upgrade dependencies + + ## 1.6.0 ### Bump dependencies diff --git a/packages/prettier-plugin-typespec/package.json b/packages/prettier-plugin-typespec/package.json index 4960e84f26d..26d88bd3c2c 100644 --- a/packages/prettier-plugin-typespec/package.json +++ b/packages/prettier-plugin-typespec/package.json @@ -1,6 +1,6 @@ { "name": "@typespec/prettier-plugin-typespec", - "version": "1.6.0", + "version": "1.7.0", "description": "", "main": "dist/index.js", "type": "module", diff --git a/packages/protobuf/CHANGELOG.md b/packages/protobuf/CHANGELOG.md index 082eaa77463..49bd989924c 100644 --- a/packages/protobuf/CHANGELOG.md +++ b/packages/protobuf/CHANGELOG.md @@ -1,5 +1,12 @@ # Change Log - @typespec/protobuf +## 0.77.0 + +### Bump dependencies + +- [#9046](https://github.com/microsoft/typespec/pull/9046) Upgrade dependencies + + ## 0.76.0 ### Bump dependencies diff --git a/packages/protobuf/package.json b/packages/protobuf/package.json index 2cafe65859f..b37bffd35a0 100644 --- a/packages/protobuf/package.json +++ b/packages/protobuf/package.json @@ -1,6 +1,6 @@ { "name": "@typespec/protobuf", - "version": "0.76.0", + "version": "0.77.0", "author": "Microsoft Corporation", "description": "TypeSpec library and emitter for Protobuf (gRPC)", "homepage": "https://github.com/microsoft/typespec", diff --git a/packages/rest/CHANGELOG.md b/packages/rest/CHANGELOG.md index 3711d8aedd4..aad753fccf7 100644 --- a/packages/rest/CHANGELOG.md +++ b/packages/rest/CHANGELOG.md @@ -1,5 +1,12 @@ # Change Log - @typespec/rest +## 0.77.0 + +### Bump dependencies + +- [#9046](https://github.com/microsoft/typespec/pull/9046) Upgrade dependencies + + ## 0.76.0 ### Bump dependencies diff --git a/packages/rest/package.json b/packages/rest/package.json index 645e1864746..945f62f4aea 100644 --- a/packages/rest/package.json +++ b/packages/rest/package.json @@ -1,6 +1,6 @@ { "name": "@typespec/rest", - "version": "0.76.0", + "version": "0.77.0", "author": "Microsoft Corporation", "description": "TypeSpec REST protocol binding", "homepage": "https://typespec.io", diff --git a/packages/spec-api/CHANGELOG.md b/packages/spec-api/CHANGELOG.md index bb6e985f7e7..5f46bc5059c 100644 --- a/packages/spec-api/CHANGELOG.md +++ b/packages/spec-api/CHANGELOG.md @@ -1,5 +1,12 @@ # @typespec/spec-api +## 0.1.0-alpha.11 + +### Bump dependencies + +- [#9046](https://github.com/microsoft/typespec/pull/9046) Upgrade dependencies + + ## 0.1.0-alpha.10 ### Bump dependencies diff --git a/packages/spec-api/package.json b/packages/spec-api/package.json index 758fb3c6fb1..ab6b51417e0 100644 --- a/packages/spec-api/package.json +++ b/packages/spec-api/package.json @@ -1,6 +1,6 @@ { "name": "@typespec/spec-api", - "version": "0.1.0-alpha.10", + "version": "0.1.0-alpha.11", "description": "Spec api to implement mock api", "type": "module", "exports": { diff --git a/packages/spec-coverage-sdk/CHANGELOG.md b/packages/spec-coverage-sdk/CHANGELOG.md index 0bf2484a496..8dc82a6b35f 100644 --- a/packages/spec-coverage-sdk/CHANGELOG.md +++ b/packages/spec-coverage-sdk/CHANGELOG.md @@ -1,5 +1,16 @@ # Change Log - @typespec/spec-coverage-sdk +## 0.1.0-alpha.13 + +### Bump dependencies + +- [#9046](https://github.com/microsoft/typespec/pull/9046) Upgrade dependencies + +### Bug Fixes + +- [#8985](https://github.com/microsoft/typespec/pull/8985) Add new `sourceUrl` handling for the go to source navigation + + ## 0.1.0-alpha.12 ### Features diff --git a/packages/spec-coverage-sdk/package.json b/packages/spec-coverage-sdk/package.json index 6e05a6647d9..a7e7f19d2d6 100644 --- a/packages/spec-coverage-sdk/package.json +++ b/packages/spec-coverage-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@typespec/spec-coverage-sdk", - "version": "0.1.0-alpha.12", + "version": "0.1.0-alpha.13", "description": "Spec utility to manage the reported coverage", "main": "dist/index.js", "type": "module", diff --git a/packages/spector/CHANGELOG.md b/packages/spector/CHANGELOG.md index 66e364cf88b..eb6025521af 100644 --- a/packages/spector/CHANGELOG.md +++ b/packages/spector/CHANGELOG.md @@ -1,5 +1,17 @@ # Change Log - @typespec/spector +## 0.1.0-alpha.21 + +### Bump dependencies + +- [#9046](https://github.com/microsoft/typespec/pull/9046) Upgrade dependencies + +### Bug Fixes + +- [#8985](https://github.com/microsoft/typespec/pull/8985) Add new `sourceUrl` handling for the go to source navigation +- [#9016](https://github.com/microsoft/typespec/pull/9016) Switch `js-yaml` to `yaml` library + + ## 0.1.0-alpha.20 ### Features diff --git a/packages/spector/package.json b/packages/spector/package.json index 530307c390f..2599a967939 100644 --- a/packages/spector/package.json +++ b/packages/spector/package.json @@ -1,6 +1,6 @@ { "name": "@typespec/spector", - "version": "0.1.0-alpha.20", + "version": "0.1.0-alpha.21", "description": "Typespec Core Tool to validate, run mock api, collect coverage.", "exports": { ".": { diff --git a/packages/sse/CHANGELOG.md b/packages/sse/CHANGELOG.md index 517eb2ff0f7..64f3cfc725c 100644 --- a/packages/sse/CHANGELOG.md +++ b/packages/sse/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog - @typespec/sse +## 0.77.0 + +### Bump dependencies + +- [#9046](https://github.com/microsoft/typespec/pull/9046) Upgrade dependencies + + ## 0.76.0 ### Bump dependencies diff --git a/packages/sse/package.json b/packages/sse/package.json index 73c6d1be2b1..ce69af519fd 100644 --- a/packages/sse/package.json +++ b/packages/sse/package.json @@ -1,6 +1,6 @@ { "name": "@typespec/sse", - "version": "0.76.0", + "version": "0.77.0", "author": "Microsoft Corporation", "description": "TypeSpec library providing server sent events bindings", "homepage": "https://typespec.io", diff --git a/packages/standalone/CHANGELOG.md b/packages/standalone/CHANGELOG.md index 64c69d2ecd6..705e5350a51 100644 --- a/packages/standalone/CHANGELOG.md +++ b/packages/standalone/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog - @typespec/standalone-cli +## 0.77.0 + +No changes, version bump only. + ## 0.76.0 No changes, version bump only. diff --git a/packages/standalone/package.json b/packages/standalone/package.json index f179f902d1d..c8d29f1d80b 100644 --- a/packages/standalone/package.json +++ b/packages/standalone/package.json @@ -1,7 +1,7 @@ { "name": "@typespec/standalone-cli", "private": true, - "version": "0.76.0", + "version": "0.77.0", "author": "Microsoft Corporation", "description": "TypeSpec Standalone CLI", "homepage": "https://typespec.io", diff --git a/packages/streams/CHANGELOG.md b/packages/streams/CHANGELOG.md index 4c8c82d304f..d8bf77f2e92 100644 --- a/packages/streams/CHANGELOG.md +++ b/packages/streams/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog - @typespec/streams +## 0.77.0 + +### Bump dependencies + +- [#9046](https://github.com/microsoft/typespec/pull/9046) Upgrade dependencies + + ## 0.76.0 ### Bump dependencies diff --git a/packages/streams/package.json b/packages/streams/package.json index 3b94481f0ea..36d9f901744 100644 --- a/packages/streams/package.json +++ b/packages/streams/package.json @@ -1,6 +1,6 @@ { "name": "@typespec/streams", - "version": "0.76.0", + "version": "0.77.0", "author": "Microsoft Corporation", "description": "TypeSpec library providing stream bindings", "homepage": "https://typespec.io", diff --git a/packages/tmlanguage-generator/CHANGELOG.md b/packages/tmlanguage-generator/CHANGELOG.md index 7f2c0701935..8230f652fa0 100644 --- a/packages/tmlanguage-generator/CHANGELOG.md +++ b/packages/tmlanguage-generator/CHANGELOG.md @@ -1,5 +1,12 @@ # Change Log - tmlanguage-generator +## 0.6.6 + +### Bump dependencies + +- [#9046](https://github.com/microsoft/typespec/pull/9046) Upgrade dependencies + + ## 0.6.5 ### Bump dependencies diff --git a/packages/tmlanguage-generator/package.json b/packages/tmlanguage-generator/package.json index 798193bca2b..c93c20fded5 100644 --- a/packages/tmlanguage-generator/package.json +++ b/packages/tmlanguage-generator/package.json @@ -1,6 +1,6 @@ { "name": "tmlanguage-generator", - "version": "0.6.5", + "version": "0.6.6", "author": "Microsoft Corporation", "description": "Helper library to generate TextMate syntax highlighting tmLanguage files.", "homepage": "https://github.com/microsoft/typespec/tree/main/packages/tmlanguage-generator", diff --git a/packages/tspd/CHANGELOG.md b/packages/tspd/CHANGELOG.md index efa678d26ac..0087acd527c 100644 --- a/packages/tspd/CHANGELOG.md +++ b/packages/tspd/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog - @typespec/tspd +## 0.73.2 + +### Bump dependencies + +- [#9046](https://github.com/microsoft/typespec/pull/9046) Upgrade dependencies + + ## 0.73.1 ### Bump dependencies diff --git a/packages/tspd/package.json b/packages/tspd/package.json index 7fa772a6038..70fa6800950 100644 --- a/packages/tspd/package.json +++ b/packages/tspd/package.json @@ -1,6 +1,6 @@ { "name": "@typespec/tspd", - "version": "0.73.1", + "version": "0.73.2", "author": "Microsoft Corporation", "description": "TypeSpec library for generating TypeSpec docs", "homepage": "https://typespec.io", diff --git a/packages/typespec-vs/CHANGELOG.md b/packages/typespec-vs/CHANGELOG.md index 854c2b95349..d353e346cc9 100644 --- a/packages/typespec-vs/CHANGELOG.md +++ b/packages/typespec-vs/CHANGELOG.md @@ -1,5 +1,9 @@ # Change Log - typespec-vs +## 1.7.0 + +No changes, version bump only. + ## 1.6.0 No changes, version bump only. diff --git a/packages/typespec-vs/package.json b/packages/typespec-vs/package.json index 8bc155228de..a56c9e0cf2b 100644 --- a/packages/typespec-vs/package.json +++ b/packages/typespec-vs/package.json @@ -1,7 +1,7 @@ { "name": "typespec-vs", "author": "Microsoft Corporation", - "version": "1.6.0", + "version": "1.7.0", "description": "TypeSpec Language Support for Visual Studio", "homepage": "https://typespec.io", "readme": "https://github.com/microsoft/typespec/blob/main/README.md", diff --git a/packages/typespec-vscode/CHANGELOG.md b/packages/typespec-vscode/CHANGELOG.md index 7f5c11d232e..c097cd5b33b 100644 --- a/packages/typespec-vscode/CHANGELOG.md +++ b/packages/typespec-vscode/CHANGELOG.md @@ -1,5 +1,12 @@ # Change Log - typespec-vscode +## 1.7.0 + +### Bump dependencies + +- [#9046](https://github.com/microsoft/typespec/pull/9046) Upgrade dependencies + + ## 1.6.0 ### Bump dependencies diff --git a/packages/typespec-vscode/package.json b/packages/typespec-vscode/package.json index 541253aed88..e66db8d94e3 100644 --- a/packages/typespec-vscode/package.json +++ b/packages/typespec-vscode/package.json @@ -1,6 +1,6 @@ { "name": "typespec-vscode", - "version": "1.6.0", + "version": "1.7.0", "author": "Microsoft Corporation", "description": "TypeSpec language support for VS Code", "homepage": "https://typespec.io", diff --git a/packages/versioning/CHANGELOG.md b/packages/versioning/CHANGELOG.md index b37beaedd00..7b2a1e857ab 100644 --- a/packages/versioning/CHANGELOG.md +++ b/packages/versioning/CHANGELOG.md @@ -1,5 +1,12 @@ # Change Log - @typespec/versioning +## 0.77.0 + +### Bump dependencies + +- [#9046](https://github.com/microsoft/typespec/pull/9046) Upgrade dependencies + + ## 0.76.0 ### Bump dependencies diff --git a/packages/versioning/package.json b/packages/versioning/package.json index 4ceec813346..6822bee770b 100644 --- a/packages/versioning/package.json +++ b/packages/versioning/package.json @@ -1,6 +1,6 @@ { "name": "@typespec/versioning", - "version": "0.76.0", + "version": "0.77.0", "author": "Microsoft Corporation", "description": "TypeSpec library for declaring and emitting versioned APIs", "homepage": "https://typespec.io", diff --git a/packages/xml/CHANGELOG.md b/packages/xml/CHANGELOG.md index ca88f31f029..f19e8067417 100644 --- a/packages/xml/CHANGELOG.md +++ b/packages/xml/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog - @typespec/xml +## 0.77.0 + +### Bump dependencies + +- [#9046](https://github.com/microsoft/typespec/pull/9046) Upgrade dependencies + + ## 0.76.0 ### Bump dependencies diff --git a/packages/xml/package.json b/packages/xml/package.json index 0c8cfc2aa10..677bd26d7ae 100644 --- a/packages/xml/package.json +++ b/packages/xml/package.json @@ -1,6 +1,6 @@ { "name": "@typespec/xml", - "version": "0.76.0", + "version": "0.77.0", "author": "Microsoft Corporation", "description": "TypeSpec library providing xml bindings", "homepage": "https://typespec.io", diff --git a/website/playground-versions.json b/website/playground-versions.json index 0d0fb90037d..2fbbe549e9e 100644 --- a/website/playground-versions.json +++ b/website/playground-versions.json @@ -1,4 +1,5 @@ [ + "1.7.x", "1.6.x", "1.5.x", "1.4.x", From 7157290fd418b81e19a56d0018ee255a23a751f0 Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Wed, 10 Dec 2025 14:27:23 +0800 Subject: [PATCH 21/40] [python] release new version (#9170) --- ...external-type-python-2025-9-20-14-28-41.md | 7 - ...ackcompatTspPadding-2025-10-18-17-23-22.md | 7 - ...-optional-properties-2025-11-3-16-16-35.md | 7 - ...l-initialization-test-2025-11-1-8-33-43.md | 7 - ...x-optional-files-part-2025-11-5-8-29-45.md | 7 - ...ix-serialization-name-2025-11-4-7-44-27.md | 7 - packages/http-client-python/CHANGELOG.md | 14 + .../eng/scripts/ci/regenerate.ts | 2 +- .../generator/test/azure/requirements.txt | 1 + .../generator/test/unbranded/requirements.txt | 1 + packages/http-client-python/package-lock.json | 1071 ++++++++--------- packages/http-client-python/package.json | 66 +- 12 files changed, 540 insertions(+), 657 deletions(-) delete mode 100644 .chronus/changes/external-type-python-2025-9-20-14-28-41.md delete mode 100644 .chronus/changes/python-backcompatTspPadding-2025-10-18-17-23-22.md delete mode 100644 .chronus/changes/python-fix-optional-properties-2025-11-3-16-16-35.md delete mode 100644 .chronus/changes/python-flatten-model-initialization-test-2025-11-1-8-33-43.md delete mode 100644 .chronus/changes/python-multipart-fix-optional-files-part-2025-11-5-8-29-45.md delete mode 100644 .chronus/changes/python-multipart-fix-serialization-name-2025-11-4-7-44-27.md diff --git a/.chronus/changes/external-type-python-2025-9-20-14-28-41.md b/.chronus/changes/external-type-python-2025-9-20-14-28-41.md deleted file mode 100644 index 2977eb159e2..00000000000 --- a/.chronus/changes/external-type-python-2025-9-20-14-28-41.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -changeKind: feature -packages: - - "@typespec/http-client-python" ---- - -Support SDK users defined customized serialization/deserialization function for external models \ No newline at end of file diff --git a/.chronus/changes/python-backcompatTspPadding-2025-10-18-17-23-22.md b/.chronus/changes/python-backcompatTspPadding-2025-10-18-17-23-22.md deleted file mode 100644 index 3d266c69f9f..00000000000 --- a/.chronus/changes/python-backcompatTspPadding-2025-10-18-17-23-22.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -changeKind: fix -packages: - - "@typespec/http-client-python" ---- - -Keep original client name for backcompat reasons when the name is only padded for tsp generations \ No newline at end of file diff --git a/.chronus/changes/python-fix-optional-properties-2025-11-3-16-16-35.md b/.chronus/changes/python-fix-optional-properties-2025-11-3-16-16-35.md deleted file mode 100644 index ac948c2b08e..00000000000 --- a/.chronus/changes/python-fix-optional-properties-2025-11-3-16-16-35.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -changeKind: fix -packages: - - "@typespec/http-client-python" ---- - -Fix for optional properties in flatten model to keep compatibility \ No newline at end of file diff --git a/.chronus/changes/python-flatten-model-initialization-test-2025-11-1-8-33-43.md b/.chronus/changes/python-flatten-model-initialization-test-2025-11-1-8-33-43.md deleted file mode 100644 index 19855d95798..00000000000 --- a/.chronus/changes/python-flatten-model-initialization-test-2025-11-1-8-33-43.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -changeKind: internal -packages: - - "@typespec/http-client-python" ---- - -Add test case for flatten model initialization to check compatibility \ No newline at end of file diff --git a/.chronus/changes/python-multipart-fix-optional-files-part-2025-11-5-8-29-45.md b/.chronus/changes/python-multipart-fix-optional-files-part-2025-11-5-8-29-45.md deleted file mode 100644 index 5e44a7a1459..00000000000 --- a/.chronus/changes/python-multipart-fix-optional-files-part-2025-11-5-8-29-45.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -changeKind: fix -packages: - - "@typespec/http-client-python" ---- - -Fix multipart when files part is optional \ No newline at end of file diff --git a/.chronus/changes/python-multipart-fix-serialization-name-2025-11-4-7-44-27.md b/.chronus/changes/python-multipart-fix-serialization-name-2025-11-4-7-44-27.md deleted file mode 100644 index d22b2a63f15..00000000000 --- a/.chronus/changes/python-multipart-fix-serialization-name-2025-11-4-7-44-27.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -changeKind: fix -packages: - - "@typespec/http-client-python" ---- - -Fix serialization name for multipart \ No newline at end of file diff --git a/packages/http-client-python/CHANGELOG.md b/packages/http-client-python/CHANGELOG.md index 8b9c0c22542..76dbabc0395 100644 --- a/packages/http-client-python/CHANGELOG.md +++ b/packages/http-client-python/CHANGELOG.md @@ -1,5 +1,19 @@ # Change Log - @typespec/http-client-python +## 0.22.0 + +### Features + +- [#8767](https://github.com/microsoft/typespec/pull/8767) Support SDK users defined customized serialization/deserialization function for external models + +### Bug Fixes + +- [#9017](https://github.com/microsoft/typespec/pull/9017) Keep original client name for backcompat reasons when the name is only padded for tsp generations +- [#9129](https://github.com/microsoft/typespec/pull/9129) Fix for optional properties in flatten model to keep compatibility +- [#9144](https://github.com/microsoft/typespec/pull/9144) Fix multipart when files part is optional +- [#9138](https://github.com/microsoft/typespec/pull/9138) Fix serialization name for multipart + + ## 0.21.0 ### Features diff --git a/packages/http-client-python/eng/scripts/ci/regenerate.ts b/packages/http-client-python/eng/scripts/ci/regenerate.ts index b13ac4cd1da..5cb3c10b843 100644 --- a/packages/http-client-python/eng/scripts/ci/regenerate.ts +++ b/packages/http-client-python/eng/scripts/ci/regenerate.ts @@ -22,7 +22,7 @@ const argv = parseArgs({ }); // Add this near the top with other constants -const SKIP_SPECS = ["type/union/discriminated"]; +const SKIP_SPECS = ["type/union/discriminated", "documentation"]; // Get the directory of the current file const PLUGIN_DIR = argv.values.pluginDir diff --git a/packages/http-client-python/generator/test/azure/requirements.txt b/packages/http-client-python/generator/test/azure/requirements.txt index 8565d622ef7..9b22f8fd14f 100644 --- a/packages/http-client-python/generator/test/azure/requirements.txt +++ b/packages/http-client-python/generator/test/azure/requirements.txt @@ -54,6 +54,7 @@ azure-mgmt-core==1.6.0 -e ./generated/setuppy-authentication-union -e ./generated/encode-duration -e ./generated/encode-numeric +-e ./generated/encode-array -e ./generated/parameters-basic -e ./generated/parameters-collection-format -e ./generated/parameters-path diff --git a/packages/http-client-python/generator/test/unbranded/requirements.txt b/packages/http-client-python/generator/test/unbranded/requirements.txt index 8ef26eadf31..7a3dde49242 100644 --- a/packages/http-client-python/generator/test/unbranded/requirements.txt +++ b/packages/http-client-python/generator/test/unbranded/requirements.txt @@ -9,6 +9,7 @@ -e ./generated/setuppy-authentication-union -e ./generated/encode-duration -e ./generated/encode-numeric +-e ./generated/encode-array -e ./generated/parameters-basic -e ./generated/parameters-collection-format -e ./generated/parameters-path diff --git a/packages/http-client-python/package-lock.json b/packages/http-client-python/package-lock.json index efc648ed32c..b68d22b8201 100644 --- a/packages/http-client-python/package-lock.json +++ b/packages/http-client-python/package-lock.json @@ -1,12 +1,12 @@ { "name": "@typespec/http-client-python", - "version": "0.21.0", + "version": "0.22.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@typespec/http-client-python", - "version": "0.21.0", + "version": "0.22.0", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -17,27 +17,27 @@ "tsx": "~4.19.1" }, "devDependencies": { - "@azure-tools/azure-http-specs": "0.1.0-alpha.32", - "@azure-tools/typespec-autorest": "~0.62.0", - "@azure-tools/typespec-azure-core": "~0.62.0", - "@azure-tools/typespec-azure-resource-manager": "~0.62.0", - "@azure-tools/typespec-azure-rulesets": "~0.62.0", - "@azure-tools/typespec-client-generator-core": "~0.62.0", + "@azure-tools/azure-http-specs": "0.1.0-alpha.33", + "@azure-tools/typespec-autorest": "~0.63.0", + "@azure-tools/typespec-azure-core": "~0.63.0", + "@azure-tools/typespec-azure-resource-manager": "~0.63.0", + "@azure-tools/typespec-azure-rulesets": "~0.63.0", + "@azure-tools/typespec-client-generator-core": "~0.63.0", "@types/js-yaml": "~4.0.5", "@types/node": "~24.1.0", "@types/semver": "7.5.8", - "@typespec/compiler": "^1.6.0", - "@typespec/events": "~0.76.0", - "@typespec/http": "^1.6.0", - "@typespec/http-specs": "0.1.0-alpha.28", - "@typespec/openapi": "^1.6.0", - "@typespec/rest": "~0.76.0", - "@typespec/spec-api": "0.1.0-alpha.10", - "@typespec/spector": "0.1.0-alpha.20", - "@typespec/sse": "~0.76.0", - "@typespec/streams": "~0.76.0", - "@typespec/versioning": "~0.76.0", - "@typespec/xml": "~0.76.0", + "@typespec/compiler": "^1.7.0", + "@typespec/events": "~0.77.0", + "@typespec/http": "^1.7.0", + "@typespec/http-specs": "0.1.0-alpha.29", + "@typespec/openapi": "^1.7.0", + "@typespec/rest": "~0.77.0", + "@typespec/spec-api": "0.1.0-alpha.11", + "@typespec/spector": "0.1.0-alpha.21", + "@typespec/sse": "~0.77.0", + "@typespec/streams": "~0.77.0", + "@typespec/versioning": "~0.77.0", + "@typespec/xml": "~0.77.0", "c8": "^10.1.3", "chalk": "5.3.0", "rimraf": "~6.0.1", @@ -49,63 +49,63 @@ "node": ">=20.0.0" }, "peerDependencies": { - "@azure-tools/typespec-autorest": ">=0.62.0 <1.0.0", - "@azure-tools/typespec-azure-core": ">=0.62.0 <1.0.0", - "@azure-tools/typespec-azure-resource-manager": ">=0.62.0 <1.0.0", - "@azure-tools/typespec-azure-rulesets": ">=0.62.0 <1.0.0", - "@azure-tools/typespec-client-generator-core": ">=0.62.0 <1.0.0", - "@typespec/compiler": "^1.6.0", - "@typespec/events": ">=0.76.0 <1.0.0", - "@typespec/http": "^1.6.0", - "@typespec/openapi": "^1.6.0", - "@typespec/rest": ">=0.76.0 <1.0.0", - "@typespec/sse": ">=0.76.0 <1.0.0", - "@typespec/streams": ">=0.76.0 <1.0.0", - "@typespec/versioning": ">=0.76.0 <1.0.0", - "@typespec/xml": ">=0.76.0 <1.0.0" + "@azure-tools/typespec-autorest": ">=0.63.0 <1.0.0", + "@azure-tools/typespec-azure-core": ">=0.63.0 <1.0.0", + "@azure-tools/typespec-azure-resource-manager": ">=0.63.0 <1.0.0", + "@azure-tools/typespec-azure-rulesets": ">=0.63.0 <1.0.0", + "@azure-tools/typespec-client-generator-core": ">=0.63.0 <1.0.0", + "@typespec/compiler": "^1.7.0", + "@typespec/events": ">=0.77.0 <1.0.0", + "@typespec/http": "^1.7.0", + "@typespec/openapi": "^1.7.0", + "@typespec/rest": ">=0.77.0 <1.0.0", + "@typespec/sse": ">=0.77.0 <1.0.0", + "@typespec/streams": ">=0.77.0 <1.0.0", + "@typespec/versioning": ">=0.77.0 <1.0.0", + "@typespec/xml": ">=0.77.0 <1.0.0" } }, "node_modules/@azure-tools/azure-http-specs": { - "version": "0.1.0-alpha.32", - "resolved": "https://registry.npmjs.org/@azure-tools/azure-http-specs/-/azure-http-specs-0.1.0-alpha.32.tgz", - "integrity": "sha512-TjPu0vZyGdAXHw1HHuExNdR2/m4JJZamrHl2TWsCOMGo1loxWVb/mTitVbi0SUkYqzKfCiKrQ+pMcHNxUvJ35Q==", + "version": "0.1.0-alpha.33", + "resolved": "https://registry.npmjs.org/@azure-tools/azure-http-specs/-/azure-http-specs-0.1.0-alpha.33.tgz", + "integrity": "sha512-AjwAF9czpgqToa5sqYZhMLSRoM9+i4O9mPxOGFqbSuGd5pfkg9TKKpGCapTT5cXnvsAx7O8fW8XxiLGMmVPF2g==", "dev": true, "license": "MIT", "dependencies": { - "@typespec/spec-api": "^0.1.0-alpha.10", - "@typespec/spector": "^0.1.0-alpha.20" + "@typespec/spec-api": "^0.1.0-alpha.11", + "@typespec/spector": "^0.1.0-alpha.21" }, "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@azure-tools/typespec-azure-core": "^0.62.0", - "@typespec/compiler": "^1.6.0", - "@typespec/http": "^1.6.0", - "@typespec/rest": "^0.76.0", - "@typespec/versioning": "^0.76.0", - "@typespec/xml": "^0.76.0" + "@azure-tools/typespec-azure-core": "^0.63.0", + "@typespec/compiler": "^1.7.0", + "@typespec/http": "^1.7.0", + "@typespec/rest": "^0.77.0", + "@typespec/versioning": "^0.77.0", + "@typespec/xml": "^0.77.0" } }, "node_modules/@azure-tools/typespec-autorest": { - "version": "0.62.0", - "resolved": "https://registry.npmjs.org/@azure-tools/typespec-autorest/-/typespec-autorest-0.62.0.tgz", - "integrity": "sha512-XftwipfGGMk9e3qGzbRMBvVpfIqLMJKc8H+XlPHFymnCfexBniZn4Qu2t8nzOVM9fgOoFDjNDzk8W5lf59U5Dg==", + "version": "0.63.0", + "resolved": "https://registry.npmjs.org/@azure-tools/typespec-autorest/-/typespec-autorest-0.63.0.tgz", + "integrity": "sha512-E04eX5axqua+bVs8QH1z74Wrq+XjO6tInq6d6EhjBNQAcRyFCJNxJHqcJkzMWNy1ID/iIGNXyRG/elK2AdegZg==", "dev": true, "license": "MIT", "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@azure-tools/typespec-azure-core": "^0.62.0", - "@azure-tools/typespec-azure-resource-manager": "^0.62.0", - "@azure-tools/typespec-client-generator-core": "^0.62.0", - "@typespec/compiler": "^1.6.0", - "@typespec/http": "^1.6.0", - "@typespec/openapi": "^1.6.0", - "@typespec/rest": "^0.76.0", - "@typespec/versioning": "^0.76.0", - "@typespec/xml": "^0.76.0" + "@azure-tools/typespec-azure-core": "^0.63.0", + "@azure-tools/typespec-azure-resource-manager": "^0.63.0", + "@azure-tools/typespec-client-generator-core": "^0.63.0", + "@typespec/compiler": "^1.7.0", + "@typespec/http": "^1.7.0", + "@typespec/openapi": "^1.7.0", + "@typespec/rest": "^0.77.0", + "@typespec/versioning": "^0.77.0", + "@typespec/xml": "^0.77.0" }, "peerDependenciesMeta": { "@typespec/xml": { @@ -114,24 +114,24 @@ } }, "node_modules/@azure-tools/typespec-azure-core": { - "version": "0.62.0", - "resolved": "https://registry.npmjs.org/@azure-tools/typespec-azure-core/-/typespec-azure-core-0.62.0.tgz", - "integrity": "sha512-4LIFqNHhKO1/jiCH0U2rfI+yH7vkWcFuwpjNyRTWXw/YghAI2d+aIEwtT4oM8jWeYR3KUQfA6AqGPRCm90AXYA==", + "version": "0.63.0", + "resolved": "https://registry.npmjs.org/@azure-tools/typespec-azure-core/-/typespec-azure-core-0.63.0.tgz", + "integrity": "sha512-FbEmpZSQENzBt/Y8qSF1b98T8CqT3bV7IRV8AGGm/73NQZiWQCm2LvQzR0/lbqGntS2EnSBrt394Kt69wM4ifA==", "dev": true, "license": "MIT", "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.6.0", - "@typespec/http": "^1.6.0", - "@typespec/rest": "^0.76.0" + "@typespec/compiler": "^1.7.0", + "@typespec/http": "^1.7.0", + "@typespec/rest": "^0.77.0" } }, "node_modules/@azure-tools/typespec-azure-resource-manager": { - "version": "0.62.0", - "resolved": "https://registry.npmjs.org/@azure-tools/typespec-azure-resource-manager/-/typespec-azure-resource-manager-0.62.0.tgz", - "integrity": "sha512-e8lO9DhIkZJ3+1o2VItq1P4gEcy9EyA5G7AhTz8qICCfU23e5xUAUfscDHYH8JAfuO9vYLvCee/MKY01MQJ0vA==", + "version": "0.63.0", + "resolved": "https://registry.npmjs.org/@azure-tools/typespec-azure-resource-manager/-/typespec-azure-resource-manager-0.63.0.tgz", + "integrity": "sha512-QXHryXgV9Rh7lBW9hrehjdGVM/W8eBN6wnfRRZtAAyfTc1AkRGDKOMFBtRtfbEkQpur16mgQTd7EyH2tpqfuSw==", "dev": true, "license": "MIT", "dependencies": { @@ -142,34 +142,34 @@ "node": ">=20.0.0" }, "peerDependencies": { - "@azure-tools/typespec-azure-core": "^0.62.0", - "@typespec/compiler": "^1.6.0", - "@typespec/http": "^1.6.0", - "@typespec/openapi": "^1.6.0", - "@typespec/rest": "^0.76.0", - "@typespec/versioning": "^0.76.0" + "@azure-tools/typespec-azure-core": "^0.63.0", + "@typespec/compiler": "^1.7.0", + "@typespec/http": "^1.7.0", + "@typespec/openapi": "^1.7.0", + "@typespec/rest": "^0.77.0", + "@typespec/versioning": "^0.77.0" } }, "node_modules/@azure-tools/typespec-azure-rulesets": { - "version": "0.62.0", - "resolved": "https://registry.npmjs.org/@azure-tools/typespec-azure-rulesets/-/typespec-azure-rulesets-0.62.0.tgz", - "integrity": "sha512-jEsR9ogSYkYxcOc5biEKbwbYS77ffD8avjT8Sbf5r+8VMPZj46uK3V0FaySbtPh+EEgoBrVj2jcbGGKDFrse1A==", + "version": "0.63.0", + "resolved": "https://registry.npmjs.org/@azure-tools/typespec-azure-rulesets/-/typespec-azure-rulesets-0.63.0.tgz", + "integrity": "sha512-oZSderD/MVnPH+W8hh3rsta1uF9xVLp9b2jjyhiHL9lqYGnHUYk8sDti5PUk/LXIz8QAsBMSbXJMDgxTeND8Kg==", "dev": true, "license": "MIT", "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@azure-tools/typespec-azure-core": "^0.62.0", - "@azure-tools/typespec-azure-resource-manager": "^0.62.0", - "@azure-tools/typespec-client-generator-core": "^0.62.0", - "@typespec/compiler": "^1.6.0" + "@azure-tools/typespec-azure-core": "^0.63.0", + "@azure-tools/typespec-azure-resource-manager": "^0.63.0", + "@azure-tools/typespec-client-generator-core": "^0.63.0", + "@typespec/compiler": "^1.7.0" } }, "node_modules/@azure-tools/typespec-client-generator-core": { - "version": "0.62.0", - "resolved": "https://registry.npmjs.org/@azure-tools/typespec-client-generator-core/-/typespec-client-generator-core-0.62.0.tgz", - "integrity": "sha512-fZilNfvqIW6Jzb97SuM5f+i9p5b0261InQRbQcTbeuYGtb5z5M0v8tuGglE4adU8NqQ1OmEv/oRjQjSeSjlxwA==", + "version": "0.63.0", + "resolved": "https://registry.npmjs.org/@azure-tools/typespec-client-generator-core/-/typespec-client-generator-core-0.63.0.tgz", + "integrity": "sha512-zpvFvjCjNW+GWzHBV7vJ2E1PKXrmyNqp7FQiYo/D7PJBVTXNtOyIKqqo043ktAaWihbr8cl5QguuNSoBAKL0+Q==", "dev": true, "license": "MIT", "dependencies": { @@ -181,16 +181,16 @@ "node": ">=20.0.0" }, "peerDependencies": { - "@azure-tools/typespec-azure-core": "^0.62.0", - "@typespec/compiler": "^1.6.0", - "@typespec/events": "^0.76.0", - "@typespec/http": "^1.6.0", - "@typespec/openapi": "^1.6.0", - "@typespec/rest": "^0.76.0", - "@typespec/sse": "^0.76.0", - "@typespec/streams": "^0.76.0", - "@typespec/versioning": "^0.76.0", - "@typespec/xml": "^0.76.0" + "@azure-tools/typespec-azure-core": "^0.63.0", + "@typespec/compiler": "^1.7.0", + "@typespec/events": "^0.77.0", + "@typespec/http": "^1.7.0", + "@typespec/openapi": "^1.7.0", + "@typespec/rest": "^0.77.0", + "@typespec/sse": "^0.77.0", + "@typespec/streams": "^0.77.0", + "@typespec/versioning": "^0.77.0", + "@typespec/xml": "^0.77.0" } }, "node_modules/@azure/abort-controller": { @@ -383,22 +383,22 @@ } }, "node_modules/@azure/msal-browser": { - "version": "4.26.1", - "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-4.26.1.tgz", - "integrity": "sha512-GGCIsZXxyNm5QcQZ4maA9q+9UWmM+/87G+ybvPkrE32el1URSa9WYt0t67ks3/P0gspZX9RoEqyLqJ/X/JDnBQ==", + "version": "4.27.0", + "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-4.27.0.tgz", + "integrity": "sha512-bZ8Pta6YAbdd0o0PEaL1/geBsPrLEnyY/RDWqvF1PP9RUH8EMLvUMGoZFYS6jSlUan6KZ9IMTLCnwpWWpQRK/w==", "dev": true, "license": "MIT", "dependencies": { - "@azure/msal-common": "15.13.1" + "@azure/msal-common": "15.13.3" }, "engines": { "node": ">=0.8.0" } }, "node_modules/@azure/msal-common": { - "version": "15.13.1", - "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-15.13.1.tgz", - "integrity": "sha512-vQYQcG4J43UWgo1lj7LcmdsGUKWYo28RfEvDQAEMmQIMjSFufvb+pS0FJ3KXmrPmnWlt1vHDl3oip6mIDUQ4uA==", + "version": "15.13.3", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-15.13.3.tgz", + "integrity": "sha512-shSDU7Ioecya+Aob5xliW9IGq1Ui8y4EVSdWGyI1Gbm4Vg61WpP95LuzcY214/wEjSn6w4PZYD4/iVldErHayQ==", "dev": true, "license": "MIT", "engines": { @@ -406,13 +406,13 @@ } }, "node_modules/@azure/msal-node": { - "version": "3.8.2", - "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-3.8.2.tgz", - "integrity": "sha512-dQrex2LiXwlCe9WuBHnCsY+xxLyuMXSd2SDEYJuhqB7cE8u6QafiC1xy8j8eBjGO30AsRi2M6amH0ZKk7vJpjA==", + "version": "3.8.4", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-3.8.4.tgz", + "integrity": "sha512-lvuAwsDpPDE/jSuVQOBMpLbXuVuLsPNRwWCyK3/6bPlBk0fGWegqoZ0qjZclMWyQ2JNvIY3vHY7hoFmFmFQcOw==", "dev": true, "license": "MIT", "dependencies": { - "@azure/msal-common": "15.13.1", + "@azure/msal-common": "15.13.3", "jsonwebtoken": "^9.0.0", "uuid": "^8.3.0" }, @@ -1101,20 +1101,30 @@ "url": "https://github.com/sponsors/nzakas" } }, + "node_modules/@inquirer/ansi": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-2.0.2.tgz", + "integrity": "sha512-SYLX05PwJVnW+WVegZt1T4Ip1qba1ik+pNJPDiqvk6zS5Y/i8PhRzLpGEtVd7sW0G8cMtkD8t4AZYhQwm8vnww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + } + }, "node_modules/@inquirer/checkbox": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.1.4.tgz", - "integrity": "sha512-d30576EZdApjAMceijXA5jDzRQHT/MygbC+J8I7EqA6f/FRpYxlRtRJbHF8gHeWYeSdOuTEJqonn7QLB1ELezA==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-5.0.2.tgz", + "integrity": "sha512-iTPV4tMMct7iOpwer5qmTP7gjnk1VQJjsNfAaC2b8Q3qiuHM3K2yjjDr5u1MKfkrvp2JD4Flf8sIPpF21pmZmw==", "dev": true, + "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.9", - "@inquirer/figures": "^1.0.11", - "@inquirer/type": "^3.0.5", - "ansi-escapes": "^4.3.2", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/ansi": "^2.0.2", + "@inquirer/core": "^11.0.2", + "@inquirer/figures": "^2.0.2", + "@inquirer/type": "^4.0.2" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -1126,16 +1136,17 @@ } }, "node_modules/@inquirer/confirm": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.8.tgz", - "integrity": "sha512-dNLWCYZvXDjO3rnQfk2iuJNL4Ivwz/T2+C3+WnNfJKsNGSuOs3wAo2F6e0p946gtSAk31nZMfW+MRmYaplPKsg==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-6.0.2.tgz", + "integrity": "sha512-A0/13Wyi+8iFeNDX6D4zZYKPoBLIEbE4K/219qHcnpXMer2weWvaTo63+2c7mQPPA206DEMSYVOPnEw3meOlCw==", "dev": true, + "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.9", - "@inquirer/type": "^3.0.5" + "@inquirer/core": "^11.0.2", + "@inquirer/type": "^4.0.2" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -1147,22 +1158,22 @@ } }, "node_modules/@inquirer/core": { - "version": "10.1.9", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.1.9.tgz", - "integrity": "sha512-sXhVB8n20NYkUBfDYgizGHlpRVaCRjtuzNZA6xpALIUbkgfd2Hjz+DfEN6+h1BRnuxw0/P4jCIMjMsEOAMwAJw==", + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-11.0.2.tgz", + "integrity": "sha512-lgMRx/n02ciiNELBvFLHtmcjbV5tf5D/I0UYfCg2YbTZWmBZ10/niLd3IjWBxz8LtM27xP+4oLEa06Slmb7p7A==", "dev": true, + "license": "MIT", "dependencies": { - "@inquirer/figures": "^1.0.11", - "@inquirer/type": "^3.0.5", - "ansi-escapes": "^4.3.2", + "@inquirer/ansi": "^2.0.2", + "@inquirer/figures": "^2.0.2", + "@inquirer/type": "^4.0.2", "cli-width": "^4.1.0", - "mute-stream": "^2.0.0", + "mute-stream": "^3.0.0", "signal-exit": "^4.1.0", - "wrap-ansi": "^6.2.0", - "yoctocolors-cjs": "^2.1.2" + "wrap-ansi": "^9.0.2" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -1174,17 +1185,18 @@ } }, "node_modules/@inquirer/editor": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.9.tgz", - "integrity": "sha512-8HjOppAxO7O4wV1ETUlJFg6NDjp/W2NP5FB9ZPAcinAlNT4ZIWOLe2pUVwmmPRSV0NMdI5r/+lflN55AwZOKSw==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-5.0.2.tgz", + "integrity": "sha512-pXQ4Nf0qmFcJuYB6NlcIIxH6l6zKOwNg1Jh/ZRdKd2dTqBB4OXKUFbFwR2K4LVXVtq15ZFFatBVT+rerYR8hWQ==", "dev": true, + "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.9", - "@inquirer/type": "^3.0.5", - "external-editor": "^3.1.0" + "@inquirer/core": "^11.0.2", + "@inquirer/external-editor": "^2.0.2", + "@inquirer/type": "^4.0.2" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -1196,17 +1208,39 @@ } }, "node_modules/@inquirer/expand": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.11.tgz", - "integrity": "sha512-OZSUW4hFMW2TYvX/Sv+NnOZgO8CHT2TU1roUCUIF2T+wfw60XFRRp9MRUPCT06cRnKL+aemt2YmTWwt7rOrNEA==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-5.0.2.tgz", + "integrity": "sha512-siFG1swxfjFIOxIcehtZkh+KUNB/YCpyfHNEGu+nC/SBXIbgUWibvThLn/WesSxLRGOeSKdNKoTm+GQCKFm6Ww==", "dev": true, + "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.9", - "@inquirer/type": "^3.0.5", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/core": "^11.0.2", + "@inquirer/type": "^4.0.2" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/external-editor": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-2.0.2.tgz", + "integrity": "sha512-X/fMXK7vXomRWEex1j8mnj7s1mpnTeP4CO/h2gysJhHLT2WjBnLv4ZQEGpm/kcYI8QfLZ2fgW+9kTKD+jeopLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chardet": "^2.1.1", + "iconv-lite": "^0.7.0" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -1218,25 +1252,27 @@ } }, "node_modules/@inquirer/figures": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.11.tgz", - "integrity": "sha512-eOg92lvrn/aRUqbxRyvpEWnrvRuTYRifixHkYVpJiygTgVSBIHDqLh0SrMQXkafvULg3ck11V7xvR+zcgvpHFw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-2.0.2.tgz", + "integrity": "sha512-qXm6EVvQx/FmnSrCWCIGtMHwqeLgxABP8XgcaAoywsL0NFga9gD5kfG0gXiv80GjK9Hsoz4pgGwF/+CjygyV9A==", "dev": true, + "license": "MIT", "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" } }, "node_modules/@inquirer/input": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.1.8.tgz", - "integrity": "sha512-WXJI16oOZ3/LiENCAxe8joniNp8MQxF6Wi5V+EBbVA0ZIOpFcL4I9e7f7cXse0HJeIPCWO8Lcgnk98juItCi7Q==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-5.0.2.tgz", + "integrity": "sha512-hN2YRo1QiEc9lD3mK+CPnTS4TK2RhCMmMmP4nCWwTkmQL2vx9jPJWYk+rbUZpwR1D583ZJk1FI3i9JZXIpi/qg==", "dev": true, + "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.9", - "@inquirer/type": "^3.0.5" + "@inquirer/core": "^11.0.2", + "@inquirer/type": "^4.0.2" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -1248,16 +1284,17 @@ } }, "node_modules/@inquirer/number": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.11.tgz", - "integrity": "sha512-pQK68CsKOgwvU2eA53AG/4npRTH2pvs/pZ2bFvzpBhrznh8Mcwt19c+nMO7LHRr3Vreu1KPhNBF3vQAKrjIulw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-4.0.2.tgz", + "integrity": "sha512-4McnjTSYrlthNW1ojkkmP75WLRYhQs7GXm6pDDoIrHqJuV5uUYwfdbB0geHdaKMarAqJQgoOVjzIT0jdWCsKew==", "dev": true, + "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.9", - "@inquirer/type": "^3.0.5" + "@inquirer/core": "^11.0.2", + "@inquirer/type": "^4.0.2" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -1269,17 +1306,18 @@ } }, "node_modules/@inquirer/password": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.11.tgz", - "integrity": "sha512-dH6zLdv+HEv1nBs96Case6eppkRggMe8LoOTl30+Gq5Wf27AO/vHFgStTVz4aoevLdNXqwE23++IXGw4eiOXTg==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-5.0.2.tgz", + "integrity": "sha512-oSDziMKiw4G2e4zS+0JRfxuPFFGh6N/9yUaluMgEHp2/Yyj2JGwfDO7XbwtOrxVrz+XsP/iaGyWXdQb9d8A0+g==", "dev": true, + "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.9", - "@inquirer/type": "^3.0.5", - "ansi-escapes": "^4.3.2" + "@inquirer/ansi": "^2.0.2", + "@inquirer/core": "^11.0.2", + "@inquirer/type": "^4.0.2" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -1291,24 +1329,25 @@ } }, "node_modules/@inquirer/prompts": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.4.0.tgz", - "integrity": "sha512-EZiJidQOT4O5PYtqnu1JbF0clv36oW2CviR66c7ma4LsupmmQlUwmdReGKRp456OWPWMz3PdrPiYg3aCk3op2w==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-8.0.2.tgz", + "integrity": "sha512-2zK5zY48fZcl6+gG4eqOC/UzZsJckHCRvjXoLuW4D8LKOCVGdcJiSKkLnumSZjR/6PXPINDGOrGHqNxb+sxJDg==", "dev": true, + "license": "MIT", "dependencies": { - "@inquirer/checkbox": "^4.1.4", - "@inquirer/confirm": "^5.1.8", - "@inquirer/editor": "^4.2.9", - "@inquirer/expand": "^4.0.11", - "@inquirer/input": "^4.1.8", - "@inquirer/number": "^3.0.11", - "@inquirer/password": "^4.0.11", - "@inquirer/rawlist": "^4.0.11", - "@inquirer/search": "^3.0.11", - "@inquirer/select": "^4.1.0" + "@inquirer/checkbox": "^5.0.2", + "@inquirer/confirm": "^6.0.2", + "@inquirer/editor": "^5.0.2", + "@inquirer/expand": "^5.0.2", + "@inquirer/input": "^5.0.2", + "@inquirer/number": "^4.0.2", + "@inquirer/password": "^5.0.2", + "@inquirer/rawlist": "^5.0.2", + "@inquirer/search": "^4.0.2", + "@inquirer/select": "^5.0.2" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -1320,17 +1359,17 @@ } }, "node_modules/@inquirer/rawlist": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.0.11.tgz", - "integrity": "sha512-uAYtTx0IF/PqUAvsRrF3xvnxJV516wmR6YVONOmCWJbbt87HcDHLfL9wmBQFbNJRv5kCjdYKrZcavDkH3sVJPg==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-5.0.2.tgz", + "integrity": "sha512-AcNALEdQKUQDeJcpC1a3YC53m1MLv+sMUS+vRZ8Qigs1Yg3Dcdtmi82rscJplogKOY8CXkKW4wvVwHS2ZjCIBQ==", "dev": true, + "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.9", - "@inquirer/type": "^3.0.5", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/core": "^11.0.2", + "@inquirer/type": "^4.0.2" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -1342,18 +1381,18 @@ } }, "node_modules/@inquirer/search": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.0.11.tgz", - "integrity": "sha512-9CWQT0ikYcg6Ls3TOa7jljsD7PgjcsYEM0bYE+Gkz+uoW9u8eaJCRHJKkucpRE5+xKtaaDbrND+nPDoxzjYyew==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-4.0.2.tgz", + "integrity": "sha512-hg63w5toohdzE65S3LiGhdfIL0kT+yisbZARf7zw65PvyMUTutTN3eMAvD/B6y/25z88vTrB7kSB45Vz5CbrXg==", "dev": true, + "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.9", - "@inquirer/figures": "^1.0.11", - "@inquirer/type": "^3.0.5", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/core": "^11.0.2", + "@inquirer/figures": "^2.0.2", + "@inquirer/type": "^4.0.2" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -1365,19 +1404,19 @@ } }, "node_modules/@inquirer/select": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.1.0.tgz", - "integrity": "sha512-z0a2fmgTSRN+YBuiK1ROfJ2Nvrpij5lVN3gPDkQGhavdvIVGHGW29LwYZfM/j42Ai2hUghTI/uoBuTbrJk42bA==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-5.0.2.tgz", + "integrity": "sha512-JygTohvQxSNnvt7IKANVlg/eds+yN5sLRilYeGc4ri/9Aqi/2QPoXBMV5Cz/L1VtQv63SnTbPXJZeCK2pSwsOA==", "dev": true, + "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.9", - "@inquirer/figures": "^1.0.11", - "@inquirer/type": "^3.0.5", - "ansi-escapes": "^4.3.2", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/ansi": "^2.0.2", + "@inquirer/core": "^11.0.2", + "@inquirer/figures": "^2.0.2", + "@inquirer/type": "^4.0.2" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -1389,12 +1428,13 @@ } }, "node_modules/@inquirer/type": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.5.tgz", - "integrity": "sha512-ZJpeIYYueOz/i/ONzrfof8g89kNdO2hjGuvULROo3O8rlB2CRtSseE5KeirnyE4t/thAn/EwvS/vuQeJCn+NZg==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.0.2.tgz", + "integrity": "sha512-cae7mzluplsjSdgFA6ACLygb5jC8alO0UUnFPyu0E7tNRPrL+q/f8VcSXp+cjZQ7l5CMpDpi2G1+IQvkOiL1Lw==", "dev": true, + "license": "MIT", "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -2092,18 +2132,18 @@ } }, "node_modules/@typespec/compiler": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@typespec/compiler/-/compiler-1.6.0.tgz", - "integrity": "sha512-yxyV+ch8tnqiuU2gClv/mQEESoFwpkjo6177UkYfV0nVA9PzTg4zVVc7+WIMZk04wiLRRT3H1uc11FB1cwLY3g==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@typespec/compiler/-/compiler-1.7.0.tgz", + "integrity": "sha512-KE2t5I7u/33M/nsIxdng06FUPrqaGSbMsSEsv51eMwYnj3v1+Z3qTTX/dxHAXRXHcfadNlX/NtyAKju+pkMTFQ==", "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "~7.27.1", - "@inquirer/prompts": "^7.4.0", + "@inquirer/prompts": "^8.0.1", "ajv": "~8.17.1", "change-case": "~5.4.4", "env-paths": "^3.0.0", - "globby": "~15.0.0", + "globby": "~16.0.0", "is-unicode-supported": "^2.1.0", "mustache": "~4.2.0", "picocolors": "~1.1.1", @@ -2124,19 +2164,6 @@ "node": ">=20.0.0" } }, - "node_modules/@typespec/compiler/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/@typespec/compiler/node_modules/cliui": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", @@ -2207,24 +2234,6 @@ "dev": true, "license": "ISC" }, - "node_modules/@typespec/compiler/node_modules/wrap-ansi": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", - "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/@typespec/compiler/node_modules/yargs": { "version": "18.0.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", @@ -2254,30 +2263,30 @@ } }, "node_modules/@typespec/events": { - "version": "0.76.0", - "resolved": "https://registry.npmjs.org/@typespec/events/-/events-0.76.0.tgz", - "integrity": "sha512-mdjYQ5HA3Y4ZeyAEmiIDdRa9hbc/5qey5hU9UCA0gL+YWVYgoqLPbZQQTwqq3smM35+5cWp9GTGPyNHcOoRwOA==", + "version": "0.77.0", + "resolved": "https://registry.npmjs.org/@typespec/events/-/events-0.77.0.tgz", + "integrity": "sha512-NbOzi7axEt/xGgXaLjcGGV2HjQKNFjbvsQpCeDA6loUghZDK5+5ik/jwMumeUDunoBsAKF78ZxVF5qhQh56dGA==", "dev": true, "license": "MIT", "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.6.0" + "@typespec/compiler": "^1.7.0" } }, "node_modules/@typespec/http": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@typespec/http/-/http-1.6.0.tgz", - "integrity": "sha512-q/JwVw21CF4buE3ZS+xSoy2TKAOwyhZ7g3kdNqCgm69BI5p5GGu+3ZlUA+4Blk8hkt0G8XcIN8fhJP+a4O6KAw==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@typespec/http/-/http-1.7.0.tgz", + "integrity": "sha512-4cGkcMiob3bedWbFkRcq614TDH7WPEI3YMgrg44mBarj903arpEniAESIhNUbLQzQFFc5rOJagexQDl4agVDyA==", "dev": true, "license": "MIT", "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.6.0", - "@typespec/streams": "^0.76.0" + "@typespec/compiler": "^1.7.0", + "@typespec/streams": "^0.77.0" }, "peerDependenciesMeta": { "@typespec/streams": { @@ -2286,59 +2295,59 @@ } }, "node_modules/@typespec/http-specs": { - "version": "0.1.0-alpha.28", - "resolved": "https://registry.npmjs.org/@typespec/http-specs/-/http-specs-0.1.0-alpha.28.tgz", - "integrity": "sha512-JnJhj/ZkmzZ4g8pnCmyP4oQQt3UbAaTGw/6SAyT8ETG+uPmrS8xgJKaxcSU1Ihaher2WY8MQ6mu7F8V+CV4e5w==", + "version": "0.1.0-alpha.29", + "resolved": "https://registry.npmjs.org/@typespec/http-specs/-/http-specs-0.1.0-alpha.29.tgz", + "integrity": "sha512-SB/NhbTllJzJchcyASixr7i+m6InyY1VjhckKiofVgU9mnoOuZTr8BQG0yrOGzWxZkm93/doDFp7kZdHSbEJQg==", "dev": true, "license": "MIT", "dependencies": { - "@typespec/spec-api": "^0.1.0-alpha.10", - "@typespec/spector": "^0.1.0-alpha.20", + "@typespec/spec-api": "^0.1.0-alpha.11", + "@typespec/spector": "^0.1.0-alpha.21", "deep-equal": "^2.2.0" }, "engines": { "node": ">=16.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.6.0", - "@typespec/http": "^1.6.0", - "@typespec/rest": "^0.76.0", - "@typespec/versioning": "^0.76.0", - "@typespec/xml": "^0.76.0" + "@typespec/compiler": "^1.7.0", + "@typespec/http": "^1.7.0", + "@typespec/rest": "^0.77.0", + "@typespec/versioning": "^0.77.0", + "@typespec/xml": "^0.77.0" } }, "node_modules/@typespec/openapi": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@typespec/openapi/-/openapi-1.6.0.tgz", - "integrity": "sha512-KuxYAzfP5ljM0PUhSGclNZgTG0H+kyTQcwn6cf4TKhO72R2QMQmiMtN2plqvzsfkL+TLwad1iZhMWTCAMFAQ4w==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@typespec/openapi/-/openapi-1.7.0.tgz", + "integrity": "sha512-tEAIgGnjLvOjbGAoCfkBudvpe/tXaOXkzy5nVFXs4921/jAaMTwzcJIt0bTXZpp5cExdlL7w9ZrnehARHiposQ==", "dev": true, "license": "MIT", "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.6.0", - "@typespec/http": "^1.6.0" + "@typespec/compiler": "^1.7.0", + "@typespec/http": "^1.7.0" } }, "node_modules/@typespec/rest": { - "version": "0.76.0", - "resolved": "https://registry.npmjs.org/@typespec/rest/-/rest-0.76.0.tgz", - "integrity": "sha512-6jtQWdcmuKyG9cmqWsJjaq64f6N5B/1DS4X3ZoTNgYhHA27Hnsxo1HZWXcpv7Wl+MxLAZM6kgpML0ugDEZcrYQ==", + "version": "0.77.0", + "resolved": "https://registry.npmjs.org/@typespec/rest/-/rest-0.77.0.tgz", + "integrity": "sha512-DEUMD9zYqUVUhKCGktV7Z+sFkzj+bcSpJRhEXxOrJxupWM4I3N4deMop+ulxezxlLxIRUz7ELc+6WucYXgOnAA==", "dev": true, "license": "MIT", "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.6.0", - "@typespec/http": "^1.6.0" + "@typespec/compiler": "^1.7.0", + "@typespec/http": "^1.7.0" } }, "node_modules/@typespec/spec-api": { - "version": "0.1.0-alpha.10", - "resolved": "https://registry.npmjs.org/@typespec/spec-api/-/spec-api-0.1.0-alpha.10.tgz", - "integrity": "sha512-LvwlhMnwqzCjmwOPuoE1jPfK+474qmo29Jq4Da2FZkjZbDsbyWuU4FRptRMhjsNj3ITMz/VulShXq4eXz4VroQ==", + "version": "0.1.0-alpha.11", + "resolved": "https://registry.npmjs.org/@typespec/spec-api/-/spec-api-0.1.0-alpha.11.tgz", + "integrity": "sha512-qNQ8Oc7ha9MzRMfcF4djRaxa7gmM9CUetNeZIVJO4PZDIe9Rb/HMX9C3LP0f5LiiYkE8KvA/jLAR4FSYqp0onA==", "dev": true, "license": "MIT", "dependencies": { @@ -2351,24 +2360,24 @@ } }, "node_modules/@typespec/spec-coverage-sdk": { - "version": "0.1.0-alpha.12", - "resolved": "https://registry.npmjs.org/@typespec/spec-coverage-sdk/-/spec-coverage-sdk-0.1.0-alpha.12.tgz", - "integrity": "sha512-eqzNQ+bZn25SP8GZyf6qgCwXL1U5/OF5AvKFl7AlYfSSuB0ybeWaDQ14jZzl5gnFXY8lCc8P0ycK1HjtwdGyqw==", + "version": "0.1.0-alpha.13", + "resolved": "https://registry.npmjs.org/@typespec/spec-coverage-sdk/-/spec-coverage-sdk-0.1.0-alpha.13.tgz", + "integrity": "sha512-GpCWrbcMQis+utHukdWdY85lNeQX89OBYiBovOxCGO5DmUmqnPQWzHZIggoAQ6fuSlC+tZoWAbY5hygN1QzPPA==", "dev": true, "license": "MIT", "dependencies": { "@azure/identity": "~4.13.0", "@azure/storage-blob": "~12.29.1", - "@types/node": "~24.9.1" + "@types/node": "~24.10.1" }, "engines": { "node": ">=16.0.0" } }, "node_modules/@typespec/spec-coverage-sdk/node_modules/@types/node": { - "version": "24.9.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.9.2.tgz", - "integrity": "sha512-uWN8YqxXxqFMX2RqGOrumsKeti4LlmIMIyV0lgut4jx7KQBcBiW6vkDtIBvHnHIquwNfJhk8v2OtmO8zXWHfPA==", + "version": "24.10.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.2.tgz", + "integrity": "sha512-WOhQTZ4G8xZ1tjJTvKOpyEVSGgOTvJAfDK3FNFgELyaTpzhdgHVHeqW8V+UJvzF5BT+/B54T/1S2K6gd9c7bbA==", "dev": true, "license": "MIT", "dependencies": { @@ -2383,32 +2392,31 @@ "license": "MIT" }, "node_modules/@typespec/spector": { - "version": "0.1.0-alpha.20", - "resolved": "https://registry.npmjs.org/@typespec/spector/-/spector-0.1.0-alpha.20.tgz", - "integrity": "sha512-qnR3NizzYu8e7TNcXY+CFp/FkXk8DJCtk3lpWPC3bNaNjxtuUjZ6Miix0gCPjDBCGOv8iquT7mLux103kMKLWQ==", + "version": "0.1.0-alpha.21", + "resolved": "https://registry.npmjs.org/@typespec/spector/-/spector-0.1.0-alpha.21.tgz", + "integrity": "sha512-oLtAs2/E+ee/OPeMZnRUxiuVjUeYaxi5R1KeFThAjLszp6M2rkCfeIdyj2RosGxiqWrmoEd9oCWO/fHwvGVZew==", "dev": true, "license": "MIT", "dependencies": { "@azure/identity": "~4.13.0", - "@types/js-yaml": "^4.0.5", - "@typespec/compiler": "^1.6.0", - "@typespec/http": "^1.6.0", - "@typespec/rest": "^0.76.0", - "@typespec/spec-api": "^0.1.0-alpha.10", - "@typespec/spec-coverage-sdk": "^0.1.0-alpha.12", - "@typespec/versioning": "^0.76.0", + "@typespec/compiler": "^1.7.0", + "@typespec/http": "^1.7.0", + "@typespec/rest": "^0.77.0", + "@typespec/spec-api": "^0.1.0-alpha.11", + "@typespec/spec-coverage-sdk": "^0.1.0-alpha.13", + "@typespec/versioning": "^0.77.0", "ajv": "~8.17.1", "body-parser": "^2.2.0", "deep-equal": "^2.2.0", "express": "^5.1.0", - "globby": "~15.0.0", - "js-yaml": "^4.1.0", + "globby": "~16.0.0", "micromatch": "^4.0.8", "morgan": "^1.10.0", "multer": "^2.0.1", "picocolors": "~1.1.1", "source-map-support": "~0.5.21", "xml2js": "^0.6.2", + "yaml": "~2.8.0", "yargs": "~18.0.0" }, "bin": { @@ -2418,19 +2426,6 @@ "node": ">=16.0.0" } }, - "node_modules/@typespec/spector/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/@typespec/spector/node_modules/cliui": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", @@ -2471,24 +2466,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@typespec/spector/node_modules/wrap-ansi": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", - "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/@typespec/spector/node_modules/yargs": { "version": "18.0.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", @@ -2518,32 +2495,32 @@ } }, "node_modules/@typespec/sse": { - "version": "0.76.0", - "resolved": "https://registry.npmjs.org/@typespec/sse/-/sse-0.76.0.tgz", - "integrity": "sha512-mCd4oAXr0Tt990T2PDjx+6H0jmPHINyCH0XRU2HrWtGW5lG/NQVIs5oOxElc7NGg629HrolfLTw0oW8hdMD7Eg==", + "version": "0.77.0", + "resolved": "https://registry.npmjs.org/@typespec/sse/-/sse-0.77.0.tgz", + "integrity": "sha512-rVML/sPNj+MomKXftko/eUNM5OhHlIevoit3Dbtaf1aWS5pcJ5jKX05Prz53VIyeUP7ra5ocmPE/iIEPb8ZbCA==", "dev": true, "license": "MIT", "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.6.0", - "@typespec/events": "^0.76.0", - "@typespec/http": "^1.6.0", - "@typespec/streams": "^0.76.0" + "@typespec/compiler": "^1.7.0", + "@typespec/events": "^0.77.0", + "@typespec/http": "^1.7.0", + "@typespec/streams": "^0.77.0" } }, "node_modules/@typespec/streams": { - "version": "0.76.0", - "resolved": "https://registry.npmjs.org/@typespec/streams/-/streams-0.76.0.tgz", - "integrity": "sha512-7gQPtsokyn0Mjr43MAik6ZkQt1PZjseU+KcBE2iGT9P6oWYYTH3K1C4LLGXHZAbgEtBvFn4S+U8HPbDhj4nEhw==", + "version": "0.77.0", + "resolved": "https://registry.npmjs.org/@typespec/streams/-/streams-0.77.0.tgz", + "integrity": "sha512-qqfJW4n19Jgi5FxQhsEgoIc5zD9o47AAoZxLKUX91z6aB/YWrLSTrrrIAvhNCESXuB89zlJPwlZ/j4YmpxZ/jw==", "dev": true, "license": "MIT", "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.6.0" + "@typespec/compiler": "^1.7.0" } }, "node_modules/@typespec/ts-http-runtime": { @@ -2562,29 +2539,29 @@ } }, "node_modules/@typespec/versioning": { - "version": "0.76.0", - "resolved": "https://registry.npmjs.org/@typespec/versioning/-/versioning-0.76.0.tgz", - "integrity": "sha512-dguO/B+mwlCyenWGG+M+16cMQuGHSTJbU5Z0pyUou1uyWrB1px//s4pW7PKD14S+fPutJE0wTMQm+CctOq6quA==", + "version": "0.77.0", + "resolved": "https://registry.npmjs.org/@typespec/versioning/-/versioning-0.77.0.tgz", + "integrity": "sha512-eAInPZYPkxpBUS8IKQfNZ5eZsLfkWqEX0d6YM/AfooGYbxcKdHQBfYOWBvRC4NkKEMub4ROaD5GcPLYTyWQIWw==", "dev": true, "license": "MIT", "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.6.0" + "@typespec/compiler": "^1.7.0" } }, "node_modules/@typespec/xml": { - "version": "0.76.0", - "resolved": "https://registry.npmjs.org/@typespec/xml/-/xml-0.76.0.tgz", - "integrity": "sha512-+I7hdWZDO3qBfzRT3St+1Dg/NQAMNLz8w1OydutSnVMx0G3KWg/ESonaByszBUfdq6Z5iTtls3gvj4wgrw80gA==", + "version": "0.77.0", + "resolved": "https://registry.npmjs.org/@typespec/xml/-/xml-0.77.0.tgz", + "integrity": "sha512-DNVAOMaRUPGpLEsqf3sn7UAWuAE1rs8Jf1FIAU7DF/sVmzeXs4OBanxSSsVmbcdfPRHPbjPuRnW6e+QS2Sjk3Q==", "dev": true, "license": "MIT", "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.6.0" + "@typespec/compiler": "^1.7.0" } }, "node_modules/@vitest/expect": { @@ -2765,21 +2742,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/ansi-regex": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", @@ -2907,37 +2869,46 @@ "license": "MIT" }, "node_modules/body-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", - "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.1.tgz", + "integrity": "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==", "dev": true, "license": "MIT", "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", - "debug": "^4.4.0", + "debug": "^4.4.3", "http-errors": "^2.0.0", - "iconv-lite": "^0.6.3", + "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", "qs": "^6.14.0", - "raw-body": "^3.0.0", - "type-is": "^2.0.0" + "raw-body": "^3.0.1", + "type-is": "^2.0.1" }, "engines": { "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/body-parser/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "node_modules/body-parser/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "dev": true, "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" + "ms": "^2.1.3" }, "engines": { - "node": ">=0.10.0" + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, "node_modules/brace-expansion": { @@ -3154,10 +3125,11 @@ "dev": true }, "node_modules/chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.1.tgz", + "integrity": "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==", + "dev": true, + "license": "MIT" }, "node_modules/check-error": { "version": "2.1.1", @@ -3184,6 +3156,7 @@ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", "dev": true, + "license": "ISC", "engines": { "node": ">= 12" } @@ -3284,16 +3257,17 @@ } }, "node_modules/content-disposition": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", - "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", + "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", "dev": true, "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/content-type": { @@ -3415,9 +3389,9 @@ "peer": true }, "node_modules/default-browser": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.3.0.tgz", - "integrity": "sha512-Qq68+VkJlc8tjnPV1i7HtbIn7ohmjZa88qUvHMIK0ZKUXMCuV45cT7cEXALPUmeXCe0q1DWQkQTemHVaLIFSrg==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.4.0.tgz", + "integrity": "sha512-XDuvSq38Hr1MdN47EDvYtx3U0MTqpCEn+F6ft8z2vYDzMrvQhVp0ui9oQdqW3MvK3vqUETglt1tVGgjLuJ5izg==", "dev": true, "license": "MIT", "dependencies": { @@ -3432,9 +3406,9 @@ } }, "node_modules/default-browser-id": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", - "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", "dev": true, "license": "MIT", "engines": { @@ -3934,19 +3908,20 @@ } }, "node_modules/express": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", - "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "dev": true, "license": "MIT", "dependencies": { "accepts": "^2.0.0", - "body-parser": "^2.2.0", + "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", + "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", @@ -3976,20 +3951,6 @@ "url": "https://opencollective.com/express" } }, - "node_modules/external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "dependencies": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -4056,9 +4017,9 @@ ] }, "node_modules/fast-xml-parser": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.3.1.tgz", - "integrity": "sha512-jbNkWiv2Ec1A7wuuxk0br0d0aTMUtQ4IkL+l/i1r9PRf6pLXjDgsBsWwO+UyczmQlnehi4Tbc8/KIvxGQe+I/A==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.3.2.tgz", + "integrity": "sha512-n8v8b6p4Z1sMgqRmqLJm3awW4NX7NkaKPfb3uJIBTSH7Pdvufi3PQ3/lJLQrvxcMYl7JI2jnDO90siPEpD8JBA==", "dev": true, "funding": [ { @@ -4109,9 +4070,9 @@ } }, "node_modules/finalhandler": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", - "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", "dev": true, "license": "MIT", "dependencies": { @@ -4123,7 +4084,11 @@ "statuses": "^2.0.1" }, "engines": { - "node": ">= 0.8" + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/find-up": { @@ -4394,18 +4359,18 @@ } }, "node_modules/globby": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-15.0.0.tgz", - "integrity": "sha512-oB4vkQGqlMl682wL1IlWd02tXCbquGWM4voPEI85QmNKCaw8zGTm1f1rubFgkg3Eli2PtKlFgrnmUqasbQWlkw==", + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-16.0.0.tgz", + "integrity": "sha512-ejy4TJFga99yW6Q0uhM3pFawKWZmtZzZD/v/GwI5+9bCV5Ew+D2pSND6W7fUes5UykqSsJkUfxFVdRh7Q1+P3Q==", "dev": true, "license": "MIT", "dependencies": { "@sindresorhus/merge-streams": "^4.0.0", "fast-glob": "^3.3.3", "ignore": "^7.0.5", - "path-type": "^6.0.0", + "is-path-inside": "^4.0.0", "slash": "^5.1.0", - "unicorn-magic": "^0.3.0" + "unicorn-magic": "^0.4.0" }, "engines": { "node": ">=20" @@ -4527,30 +4492,24 @@ "dev": true }, "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "dev": true, "license": "MIT", "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" }, "engines": { "node": ">= 0.8" - } - }, - "node_modules/http-errors/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/http-proxy-agent": { @@ -4582,15 +4541,20 @@ } }, "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", + "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", "dev": true, + "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/ignore": { @@ -4864,6 +4828,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-path-inside": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz", + "integrity": "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-promise": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", @@ -5116,13 +5093,13 @@ "peer": true }, "node_modules/jsonwebtoken": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", - "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", + "integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==", "dev": true, "license": "MIT", "dependencies": { - "jws": "^3.2.2", + "jws": "^4.0.1", "lodash.includes": "^4.3.0", "lodash.isboolean": "^3.0.3", "lodash.isinteger": "^4.0.4", @@ -5139,9 +5116,9 @@ } }, "node_modules/jwa": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz", - "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", "dev": true, "license": "MIT", "dependencies": { @@ -5151,13 +5128,13 @@ } }, "node_modules/jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", "dev": true, "license": "MIT", "dependencies": { - "jwa": "^1.4.1", + "jwa": "^2.0.1", "safe-buffer": "^5.0.1" } }, @@ -5374,16 +5351,20 @@ } }, "node_modules/mime-types": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", - "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "dev": true, "license": "MIT", "dependencies": { "mime-db": "^1.54.0" }, "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/minimatch": { @@ -5574,12 +5555,13 @@ } }, "node_modules/mute-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", - "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-3.0.0.tgz", + "integrity": "sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==", "dev": true, + "license": "ISC", "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/nanoid": { @@ -5758,15 +5740,6 @@ "node": ">= 0.8.0" } }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -5871,19 +5844,6 @@ "url": "https://opencollective.com/express" } }, - "node_modules/path-type": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz", - "integrity": "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/pathe": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", @@ -6075,38 +6035,21 @@ } }, "node_modules/raw-body": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.1.tgz", - "integrity": "sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", "dev": true, "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.7.0", - "unpipe": "1.0.0" + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.10" } }, - "node_modules/raw-body/node_modules/iconv-lite": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", - "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -6344,7 +6287,8 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/sax": { "version": "1.4.3", @@ -7015,18 +6959,6 @@ "node": ">=14.0.0" } }, - "node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -7099,18 +7031,6 @@ "node": ">= 0.8.0" } }, - "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/type-is": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", @@ -7177,13 +7097,13 @@ "license": "MIT" }, "node_modules/unicorn-magic": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", - "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.4.0.tgz", + "integrity": "sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==", "dev": true, "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -7611,17 +7531,21 @@ } }, "node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, "node_modules/wrap-ansi-cjs": { @@ -7683,45 +7607,42 @@ "node": ">=8" } }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/wrap-ansi/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" }, "node_modules/wrap-ansi/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, + "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" + "node": ">=18" }, - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/wrappy": { @@ -7912,18 +7833,6 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } - }, - "node_modules/yoctocolors-cjs": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz", - "integrity": "sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==", - "dev": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } } } } diff --git a/packages/http-client-python/package.json b/packages/http-client-python/package.json index 4afb30ea8da..e0b07cff644 100644 --- a/packages/http-client-python/package.json +++ b/packages/http-client-python/package.json @@ -1,6 +1,6 @@ { "name": "@typespec/http-client-python", - "version": "0.21.0", + "version": "0.22.0", "author": "Microsoft Corporation", "description": "TypeSpec emitter for Python SDKs", "homepage": "https://typespec.io", @@ -54,20 +54,20 @@ "emitter" ], "peerDependencies": { - "@azure-tools/typespec-autorest": ">=0.62.0 <1.0.0", - "@azure-tools/typespec-azure-core": ">=0.62.0 <1.0.0", - "@azure-tools/typespec-azure-resource-manager": ">=0.62.0 <1.0.0", - "@azure-tools/typespec-azure-rulesets": ">=0.62.0 <1.0.0", - "@azure-tools/typespec-client-generator-core": ">=0.62.0 <1.0.0", - "@typespec/compiler": "^1.6.0", - "@typespec/http": "^1.6.0", - "@typespec/openapi": "^1.6.0", - "@typespec/rest": ">=0.76.0 <1.0.0", - "@typespec/versioning": ">=0.76.0 <1.0.0", - "@typespec/events": ">=0.76.0 <1.0.0", - "@typespec/sse": ">=0.76.0 <1.0.0", - "@typespec/streams": ">=0.76.0 <1.0.0", - "@typespec/xml": ">=0.76.0 <1.0.0" + "@azure-tools/typespec-autorest": ">=0.63.0 <1.0.0", + "@azure-tools/typespec-azure-core": ">=0.63.0 <1.0.0", + "@azure-tools/typespec-azure-resource-manager": ">=0.63.0 <1.0.0", + "@azure-tools/typespec-azure-rulesets": ">=0.63.0 <1.0.0", + "@azure-tools/typespec-client-generator-core": ">=0.63.0 <1.0.0", + "@typespec/compiler": "^1.7.0", + "@typespec/http": "^1.7.0", + "@typespec/openapi": "^1.7.0", + "@typespec/rest": ">=0.77.0 <1.0.0", + "@typespec/versioning": ">=0.77.0 <1.0.0", + "@typespec/events": ">=0.77.0 <1.0.0", + "@typespec/sse": ">=0.77.0 <1.0.0", + "@typespec/streams": ">=0.77.0 <1.0.0", + "@typespec/xml": ">=0.77.0 <1.0.0" }, "dependencies": { "js-yaml": "~4.1.0", @@ -77,24 +77,24 @@ "tsx": "~4.19.1" }, "devDependencies": { - "@azure-tools/typespec-autorest": "~0.62.0", - "@azure-tools/typespec-azure-core": "~0.62.0", - "@azure-tools/typespec-azure-resource-manager": "~0.62.0", - "@azure-tools/typespec-azure-rulesets": "~0.62.0", - "@azure-tools/typespec-client-generator-core": "~0.62.0", - "@azure-tools/azure-http-specs": "0.1.0-alpha.32", - "@typespec/compiler": "^1.6.0", - "@typespec/http": "^1.6.0", - "@typespec/openapi": "^1.6.0", - "@typespec/rest": "~0.76.0", - "@typespec/versioning": "~0.76.0", - "@typespec/events": "~0.76.0", - "@typespec/spector": "0.1.0-alpha.20", - "@typespec/spec-api": "0.1.0-alpha.10", - "@typespec/sse": "~0.76.0", - "@typespec/streams": "~0.76.0", - "@typespec/xml": "~0.76.0", - "@typespec/http-specs": "0.1.0-alpha.28", + "@azure-tools/typespec-autorest": "~0.63.0", + "@azure-tools/typespec-azure-core": "~0.63.0", + "@azure-tools/typespec-azure-resource-manager": "~0.63.0", + "@azure-tools/typespec-azure-rulesets": "~0.63.0", + "@azure-tools/typespec-client-generator-core": "~0.63.0", + "@azure-tools/azure-http-specs": "0.1.0-alpha.33", + "@typespec/compiler": "^1.7.0", + "@typespec/http": "^1.7.0", + "@typespec/openapi": "^1.7.0", + "@typespec/rest": "~0.77.0", + "@typespec/versioning": "~0.77.0", + "@typespec/events": "~0.77.0", + "@typespec/spector": "0.1.0-alpha.21", + "@typespec/spec-api": "0.1.0-alpha.11", + "@typespec/sse": "~0.77.0", + "@typespec/streams": "~0.77.0", + "@typespec/xml": "~0.77.0", + "@typespec/http-specs": "0.1.0-alpha.29", "@types/js-yaml": "~4.0.5", "@types/node": "~24.1.0", "@types/semver": "7.5.8", From a5efa3c702691525221bf2d8f2cfc5d8a8a83891 Mon Sep 17 00:00:00 2001 From: Jorge Rangel <102122018+jorgerangel-msft@users.noreply.github.com> Date: Wed, 10 Dec 2025 11:05:25 -0600 Subject: [PATCH 22/40] Make equality comparer for CSharpType public (#9169) Follow up to : https://github.com/microsoft/typespec/pull/9166. This exposes the internal CSharpType comparer, to be consumed by the azure generator in it's serialization hooks. --- .../Microsoft.TypeSpec.Generator/src/Primitives/CSharpType.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Primitives/CSharpType.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Primitives/CSharpType.cs index 3538b8b926c..2c4de605e0d 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Primitives/CSharpType.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Primitives/CSharpType.cs @@ -694,7 +694,7 @@ internal void Update(string? name = null, string? @namespace = null) internal static readonly IEqualityComparer IgnoreNullableComparer = new CSharpTypeIgnoreNullableComparer(); - private class CSharpTypeIgnoreNullableComparer : IEqualityComparer + public sealed class CSharpTypeIgnoreNullableComparer : IEqualityComparer { public bool Equals(CSharpType? x, CSharpType? y) { From cea1774f044a708a48ea4b099e933a6d9c1ec2c0 Mon Sep 17 00:00:00 2001 From: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com> Date: Wed, 10 Dec 2025 10:27:14 -0800 Subject: [PATCH 23/40] Don't call non-existent deserialize method for framework types (#9177) Co-authored-by: Jorge Rangel <102122018+jorgerangel-msft@users.noreply.github.com> --- .../MrwSerializationTypeDefinition.Dynamic.cs | 13 - .../MrwSerializationTypeDefinition.cs | 20 +- .../MrwSerializationTypeDefinitionTests.cs | 301 ++++++++++++++++++ 3 files changed, 319 insertions(+), 15 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Dynamic.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Dynamic.cs index 145f4f28598..c62dfd0df8b 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Dynamic.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Dynamic.cs @@ -13,25 +13,12 @@ using Microsoft.TypeSpec.Generator.Providers; using Microsoft.TypeSpec.Generator.Snippets; using Microsoft.TypeSpec.Generator.Statements; -using static System.Runtime.InteropServices.JavaScript.JSType; using static Microsoft.TypeSpec.Generator.Snippets.Snippet; namespace Microsoft.TypeSpec.Generator.ClientModel.Providers { public partial class MrwSerializationTypeDefinition { - internal static ValueExpression GetDeserializationMethodInvocationForType( - CSharpType modelType, - ScopedApi jsonElementVariable, - ValueExpression dataVariable, - ValueExpression? optionsVariable = null) - { - return ScmCodeModelGenerator.Instance.TypeFactory.CSharpTypeMap.TryGetValue(modelType, out var provider) && - provider is ModelProvider modelProvider - ? GetDeserializationMethodInvocationForType(modelProvider, jsonElementVariable, dataVariable, optionsVariable) - : modelType.Deserialize(jsonElementVariable, null, optionsVariable); - } - #pragma warning disable SCME0001 // Type is for evaluation purposes only and is subject to change or removal in future updates. private MethodBodyStatement CreateDictionarySerializationWithPatch( DictionaryExpression dictionary, diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs index 4eb94e9ba34..0298795e5de 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs @@ -1993,9 +1993,13 @@ Type t when ValueTypeIsInt(t) => { ScmCodeModelGenerator.Instance.Emitter.ReportDiagnostic( DiagnosticCodes.UnsupportedSerialization, - $"Deserialization of type {valueType.Name} is not supported.", + $"Deserialization of type {valueType.Name} may not be supported using MRW serialization.", severity: EmitterDiagnosticSeverity.Warning); - return GetDeserializationMethodInvocationForType(valueType, element, data, mrwOptions); + // Fall back to MRW deserialization for framework type + return Static(typeof(ModelReaderWriter)).Invoke( + nameof(ModelReaderWriter.Read), + [data, ModelSerializationExtensionsSnippets.Wire, ModelReaderWriterContextSnippets.Default], + [valueType]); } return exp; @@ -2217,5 +2221,17 @@ private static bool TypeRequiresNullCheckInSerialization(CSharpType type) return false; } + + internal static ValueExpression GetDeserializationMethodInvocationForType( + CSharpType modelType, + ScopedApi jsonElementVariable, + ValueExpression dataVariable, + ValueExpression? optionsVariable = null) + { + return ScmCodeModelGenerator.Instance.TypeFactory.CSharpTypeMap.TryGetValue(modelType, out var provider) && + provider is ModelProvider modelProvider + ? GetDeserializationMethodInvocationForType(modelProvider, jsonElementVariable, dataVariable, optionsVariable) + : modelType.Deserialize(jsonElementVariable, null, optionsVariable); + } } } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/MrwSerializationTypeDefinitionTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/MrwSerializationTypeDefinitionTests.cs index 00d90346026..621f52b1671 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/MrwSerializationTypeDefinitionTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/MrwSerializationTypeDefinitionTests.cs @@ -924,5 +924,306 @@ protected override PropertyProvider[] BuildProperties() MethodBodyStatements statements => statements.Statements.Any(s => HasMethodBodyStatement(s, predicate)), _ => predicate(statement) }; + + [Test] + public void TestGetDeserializationMethodInvocationForType_FrameworkType() + { + MockHelpers.LoadMockGenerator(); + // Test that framework types are handled via DeserializeJsonValueCore + // which uses MRW.Read as a fallback for unsupported types + var jsonElementVar = new ScopedApi(new VariableExpression(typeof(JsonElement), "element")); + var dataVar = new VariableExpression(typeof(BinaryData), "data"); + var optionsVar = new VariableExpression(typeof(ModelReaderWriterOptions), "options"); + + // String is a framework type that should be handled by DeserializeJsonValueCore + var frameworkType = new CSharpType(typeof(string)); + var result = MrwSerializationTypeDefinition.GetDeserializationMethodInvocationForType( + frameworkType, + jsonElementVar, + dataVar, + optionsVar); + + Assert.IsNotNull(result); + var resultString = result.ToDisplayString(); + // Framework types now go through the type's Deserialize method + Assert.IsTrue(resultString.Contains("Deserialize")); + } + + [Test] + public void TestGetDeserializationMethodInvocationForType_ModelType() + { + MockHelpers.LoadMockGenerator(); + // Test that model types use the model's deserialize method + var inputModel = InputFactory.Model("TestModel"); + var (model, _) = CreateModelAndSerialization(inputModel); + + var jsonElementVar = new ScopedApi(new VariableExpression(typeof(JsonElement), "element")); + var dataVar = new VariableExpression(typeof(BinaryData), "data"); + var optionsVar = new VariableExpression(typeof(ModelReaderWriterOptions), "options"); + + var result = MrwSerializationTypeDefinition.GetDeserializationMethodInvocationForType( + model.Type, + jsonElementVar, + dataVar, + optionsVar); + + Assert.IsNotNull(result); + var resultString = result.ToDisplayString(); + // Model types should use the Deserialize extension method + Assert.IsTrue(resultString.Contains("Deserialize")); + Assert.IsTrue(resultString.Contains("TestModel")); + } + + [Test] + public void TestGetDeserializationMethodInvocationForType_NonModelCSharpType() + { + MockHelpers.LoadMockGenerator(); + // Test that non-model CSharpTypes use the type's deserialize method + var jsonElementVar = new ScopedApi(new VariableExpression(typeof(JsonElement), "element")); + var dataVar = new VariableExpression(typeof(BinaryData), "data"); + var optionsVar = new VariableExpression(typeof(ModelReaderWriterOptions), "options"); + + // Use a type that's not in the type factory + var customType = new CSharpType(typeof(int)); + var result = MrwSerializationTypeDefinition.GetDeserializationMethodInvocationForType( + customType, + jsonElementVar, + dataVar, + optionsVar); + + Assert.IsNotNull(result); + var resultString = result.ToDisplayString(); + // Should call Deserialize on the type + Assert.IsTrue(resultString.Contains("Deserialize")); + } + + [Test] + public void TestGetDeserializationMethodInvocationForType_WithoutOptions() + { + MockHelpers.LoadMockGenerator(); + // Test that the method works when options are not provided + var jsonElementVar = new ScopedApi(new VariableExpression(typeof(JsonElement), "element")); + var dataVar = new VariableExpression(typeof(BinaryData), "data"); + + var frameworkType = new CSharpType(typeof(string)); + var result = MrwSerializationTypeDefinition.GetDeserializationMethodInvocationForType( + frameworkType, + jsonElementVar, + dataVar, + null); + + Assert.IsNotNull(result); + var resultString = result.ToDisplayString(); + // Should still deserialize even without options parameter + Assert.IsTrue(resultString.Contains("Deserialize")); + } + + [Test] + public void TestDeserializeJsonValueCore_FrameworkTypeWithMrwFallback() + { + MockHelpers.LoadMockGenerator(); + // Test that DeserializeJsonValueCore uses MRW fallback for unsupported framework types + var jsonElementVar = new ScopedApi(new VariableExpression(typeof(JsonElement), "element")); + var dataVar = new ScopedApi(new VariableExpression(typeof(BinaryData), "data")); + var optionsVar = new ScopedApi(new VariableExpression(typeof(ModelReaderWriterOptions), "options")); + + // Use a framework type that's not explicitly handled in DeserializeJsonValueCore + // This should fall back to ModelReaderWriter.Read + var unsupportedType = new CSharpType(typeof(System.Reflection.Assembly)); + var result = MrwSerializationTypeDefinition.DeserializeJsonValueCore( + unsupportedType, + jsonElementVar, + dataVar, + optionsVar, + SerializationFormat.Default); + + Assert.IsNotNull(result); + var resultString = result.ToDisplayString(); + // Should use MRW.Read as fallback + Assert.IsTrue(resultString.Contains("global::System.ClientModel.Primitives.ModelReaderWriter.Read")); + Assert.IsTrue(resultString.Contains("data")); + } + + [Test] + public void TestDeserializeJsonValueCore_SupportedFrameworkTypes() + { + MockHelpers.LoadMockGenerator(); + // Test that common framework types are handled correctly without MRW fallback + var jsonElementVar = new ScopedApi(new VariableExpression(typeof(JsonElement), "element")); + var dataVar = new ScopedApi(new VariableExpression(typeof(BinaryData), "data")); + var optionsVar = new ScopedApi(new VariableExpression(typeof(ModelReaderWriterOptions), "options")); + + // Test string + var stringResult = MrwSerializationTypeDefinition.DeserializeJsonValueCore( + new CSharpType(typeof(string)), + jsonElementVar, + dataVar, + optionsVar, + SerializationFormat.Default); + Assert.IsTrue(stringResult.ToDisplayString().Contains("GetString")); + + // Test int + var intResult = MrwSerializationTypeDefinition.DeserializeJsonValueCore( + new CSharpType(typeof(int)), + jsonElementVar, + dataVar, + optionsVar, + SerializationFormat.Default); + Assert.IsTrue(intResult.ToDisplayString().Contains("GetInt32")); + + // Test bool + var boolResult = MrwSerializationTypeDefinition.DeserializeJsonValueCore( + new CSharpType(typeof(bool)), + jsonElementVar, + dataVar, + optionsVar, + SerializationFormat.Default); + Assert.IsTrue(boolResult.ToDisplayString().Contains("GetBoolean")); + } + + [Test] + public void TestGetDeserializationMethodInvocationForType_DynamicModel() + { + MockHelpers.LoadMockGenerator(); + // Test that dynamic models handle data parameter correctly + var properties = new List + { + InputFactory.Property("prop1", InputPrimitiveType.String, isRequired: true) + }; + + var inputModel = InputFactory.Model("DynamicModel", properties: properties, modelAsStruct: false); + MockHelpers.LoadMockGenerator(); + + // Create a model provider + var modelProvider = ScmCodeModelGenerator.Instance.TypeFactory.CreateModel(inputModel) as ModelProvider; + Assert.IsNotNull(modelProvider); + + var jsonElementVar = new ScopedApi(new VariableExpression(typeof(JsonElement), "element")); + var dataVar = new VariableExpression(typeof(BinaryData), "data"); + var optionsVar = new VariableExpression(typeof(ModelReaderWriterOptions), "options"); + + // Call the internal method directly from the test assembly + var result = MrwSerializationTypeDefinition.GetDeserializationMethodInvocationForType( + modelProvider!.Type, + jsonElementVar, + dataVar, + optionsVar); + + Assert.IsNotNull(result); + var resultString = result.ToDisplayString(); + Assert.IsTrue(resultString.Contains("Deserialize")); + } + + [Test] + public void TestGetDeserializationMethodInvocationForType_InDeserializationMethod() + { + MockHelpers.LoadMockGenerator(); + // Test that GetDeserializationMethodInvocationForType is used correctly in the deserialization method + var properties = new List + { + InputFactory.Property("modelProperty", InputFactory.Model("InnerModel"), isRequired: true) + }; + + var innerModel = InputFactory.Model("InnerModel"); + var inputModel = InputFactory.Model("OuterModel", properties: properties); + + var generator = MockHelpers.LoadMockGenerator( + inputModels: () => [inputModel, innerModel], + createSerializationsCore: (inputType, typeProvider) => + inputType is InputModelType modelType ? [new MrwSerializationTypeDefinition(modelType, (typeProvider as ModelProvider)!)]: []); + + generator.Object.TypeFactory.RootInputModels.Add(inputModel); + generator.Object.TypeFactory.RootOutputModels.Add(inputModel); + generator.Object.TypeFactory.RootInputModels.Add(innerModel); + generator.Object.TypeFactory.RootOutputModels.Add(innerModel); + + var outerModel = ScmCodeModelGenerator.Instance.TypeFactory.CreateModel(inputModel) as ModelProvider; + Assert.IsNotNull(outerModel); + + var serialization = outerModel!.SerializationProviders.FirstOrDefault() as MrwSerializationTypeDefinition; + Assert.IsNotNull(serialization); + + var deserializationMethod = serialization!.BuildDeserializationMethod(); + Assert.IsNotNull(deserializationMethod); + + var methodBody = deserializationMethod!.BodyStatements!.ToDisplayString(); + // Verify that the deserialization method contains calls to deserialize the inner model + Assert.IsTrue(methodBody.Contains("InnerModel")); + Assert.IsTrue(methodBody.Contains("Deserialize")); + } + + [Test] + public void TestGetDeserializationMethodInvocationForType_CollectionOfModels() + { + MockHelpers.LoadMockGenerator(); + // Test deserialization of collections containing model types + var innerModel = InputFactory.Model("ItemModel"); + var properties = new List + { + InputFactory.Property("items", InputFactory.Array(innerModel), isRequired: true) + }; + + var inputModel = InputFactory.Model("CollectionModel", properties: properties); + + var generator = MockHelpers.LoadMockGenerator( + inputModels: () => [inputModel, innerModel], + createSerializationsCore: (inputType, typeProvider) => + inputType is InputModelType modelType ? [new MrwSerializationTypeDefinition(modelType, (typeProvider as ModelProvider)!)]: []); + + generator.Object.TypeFactory.RootInputModels.Add(inputModel); + generator.Object.TypeFactory.RootOutputModels.Add(inputModel); + generator.Object.TypeFactory.RootInputModels.Add(innerModel); + generator.Object.TypeFactory.RootOutputModels.Add(innerModel); + + var model = ScmCodeModelGenerator.Instance.TypeFactory.CreateModel(inputModel) as ModelProvider; + Assert.IsNotNull(model); + + var serialization = model!.SerializationProviders.FirstOrDefault() as MrwSerializationTypeDefinition; + Assert.IsNotNull(serialization); + + var deserializationMethod = serialization!.BuildDeserializationMethod(); + Assert.IsNotNull(deserializationMethod); + + var methodBody = deserializationMethod!.BodyStatements!.ToDisplayString(); + // Verify that array deserialization includes item model deserialization + Assert.IsTrue(methodBody.Contains("ItemModel")); + } + + [Test] + public void TestGetDeserializationMethodInvocationForType_DictionaryOfModels() + { + MockHelpers.LoadMockGenerator(); + // Test deserialization of dictionaries with model values + var valueModel = InputFactory.Model("ValueModel"); + var properties = new List + { + InputFactory.Property("values", InputFactory.Dictionary(valueModel), isRequired: true) + }; + + var inputModel = InputFactory.Model("DictionaryModel", properties: properties); + + var generator = MockHelpers.LoadMockGenerator( + inputModels: () => [inputModel, valueModel], + createSerializationsCore: (inputType, typeProvider) => + inputType is InputModelType modelType ? [new MrwSerializationTypeDefinition(modelType, (typeProvider as ModelProvider)!)]: []); + + generator.Object.TypeFactory.RootInputModels.Add(inputModel); + generator.Object.TypeFactory.RootOutputModels.Add(inputModel); + generator.Object.TypeFactory.RootInputModels.Add(valueModel); + generator.Object.TypeFactory.RootOutputModels.Add(valueModel); + + var model = ScmCodeModelGenerator.Instance.TypeFactory.CreateModel(inputModel) as ModelProvider; + Assert.IsNotNull(model); + + var serialization = model!.SerializationProviders.FirstOrDefault() as MrwSerializationTypeDefinition; + Assert.IsNotNull(serialization); + + var deserializationMethod = serialization!.BuildDeserializationMethod(); + Assert.IsNotNull(deserializationMethod); + + var methodBody = deserializationMethod!.BodyStatements!.ToDisplayString(); + // Verify that dictionary deserialization includes value model deserialization + Assert.IsTrue(methodBody.Contains("ValueModel")); + } } } From 4a728cbbf97413e80849738c66d39253fb04b550 Mon Sep 17 00:00:00 2001 From: Will Temple Date: Wed, 10 Dec 2025 13:47:00 -0500 Subject: [PATCH 24/40] hsjs: fix handling of optional query/header params (#9176) These use a different codepath in HSJS than JSON properties, and that codepath was mishandling optional parameters by unconditionally passing them into `globalThis.Number`/`globalThis.Boolean`, etc. This patch adds an explicit check for `undefined` and transposes that to `undefined` instead of calling the parser unconditionally, which will return the default value. For parsers that don't accept `undefined` as an input, this would have triggered a type error or runtime error. Closes #9156 --- ...msft-hsjs-hyperparam-optionality-2025-11-10-11-43-24.md | 7 +++++++ packages/http-server-js/src/http/server/index.ts | 6 +++++- 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 .chronus/changes/witemple-msft-hsjs-hyperparam-optionality-2025-11-10-11-43-24.md diff --git a/.chronus/changes/witemple-msft-hsjs-hyperparam-optionality-2025-11-10-11-43-24.md b/.chronus/changes/witemple-msft-hsjs-hyperparam-optionality-2025-11-10-11-43-24.md new file mode 100644 index 00000000000..0fab7340042 --- /dev/null +++ b/.chronus/changes/witemple-msft-hsjs-hyperparam-optionality-2025-11-10-11-43-24.md @@ -0,0 +1,7 @@ +--- +changeKind: fix +packages: + - "@typespec/http-server-js" +--- + +Fixed a bug that caused optional query/header parameters to be improperly converted to primitive types when not provided in a request. \ No newline at end of file diff --git a/packages/http-server-js/src/http/server/index.ts b/packages/http-server-js/src/http/server/index.ts index 76717b5d215..a54351ccc7b 100644 --- a/packages/http-server-js/src/http/server/index.ts +++ b/packages/http-server-js/src/http/server/index.ts @@ -425,7 +425,11 @@ function* emitRawServerOperation( const encoder = jsScalar.http[httpOperationParam.type]; - paramBaseExpression = encoder.decode(paramNameSafe); + const decoded = encoder.decode(paramNameSafe); + + paramBaseExpression = param.optional + ? `${paramNameSafe} === undefined ? undefined : (${decoded})` + : decoded; } else { paramBaseExpression = paramNameSafe; } From 3317b787ab5a2e6398d10998ea5cda898e06cf2c Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Thu, 11 Dec 2025 13:51:01 +0800 Subject: [PATCH 25/40] Allow customization of base model when spec defines a base model (#9181) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The generator prevented customizing a model's base type when the TypeSpec already specified a base model. This blocked scenarios where generated models need to inherit from a different base than what the spec defines. ## Changes - **Modified `ModelProvider.BuildBaseModelProvider()`**: Check for `CustomCodeView?.BaseType` before falling back to `_inputModel.BaseModel`, enabling custom base types to override spec-defined base models - **Added test `CanCustomizeBaseModelWithSpecBase`**: Verifies that a model with a spec-defined base can be customized to inherit from a different base model instead ## Example Given a TypeSpec model with a base: ```csharp // Spec defines: MockInputModel extends SpecBaseModel ``` Users can now customize it to use a different base: ```csharp namespace Sample.Models { public partial class MockInputModel : CustomBaseModel // Overrides spec base { } } ``` The generated code will respect the custom base type instead of the spec-defined one.
Original prompt > > ---- > > *This section details on the original issue you should resolve* > > Unable to customize base model of generated model if spec has a base model > In MTG, we can only customize base model if input model doesn't have a base model already. > https://github.com/microsoft/typespec/blob/fecf4f2300b88dc663f27dcb3f37bff78313a17b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs#L245-L250 > > There are cases, we need to customize the base model even the spec has specified the base model. > > remove the input model base model check and add a unit test to verify the scenario > > ## Comments on the Issue (you are @copilot in this section) > > > >
- Fixes microsoft/typespec#9180 --- 💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more [Copilot coding agent tips](https://gh.io/copilot-coding-agent-tips) in the docs. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: live1206 <5196139+live1206@users.noreply.github.com> --- .../src/Providers/ModelProvider.cs | 40 +++++++++---------- .../ModelProviders/ModelCustomizationTests.cs | 32 +++++++++++++++ .../MockInputModel.cs | 11 +++++ 3 files changed, 63 insertions(+), 20 deletions(-) create mode 100644 packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CanCustomizeBaseModelWithSpecBase/MockInputModel.cs diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs index b126b0338ad..c3ccaab3f69 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs @@ -242,32 +242,32 @@ private static bool IsDiscriminator(InputProperty property) private ModelProvider? BuildBaseModelProvider() { - if (_inputModel.BaseModel == null) + // consider models that have been customized to inherit from a different model + if (CustomCodeView?.BaseType != null) { - // consider models that have been customized to inherit from a different model - if (CustomCodeView?.BaseType != null) - { - var baseType = CustomCodeView.BaseType; + var baseType = CustomCodeView.BaseType; - // If the custom base type doesn't have a resolved namespace, then try to resolve it from the input model map. - // This will happen if a model is customized to inherit from another generated model, but that generated model - // was not also defined in custom code so Roslyn does not recognize it. - if (string.IsNullOrEmpty(baseType.Namespace)) - { - if (CodeModelGenerator.Instance.TypeFactory.InputModelTypeNameMap.TryGetValue(baseType.Name, out var baseInputModel)) - { - baseType = CodeModelGenerator.Instance.TypeFactory.CreateCSharpType(baseInputModel); - } - } - if (baseType != null && CodeModelGenerator.Instance.TypeFactory.CSharpTypeMap.TryGetValue( - baseType, - out var customBaseType) && - customBaseType is ModelProvider customBaseModel) + // If the custom base type doesn't have a resolved namespace, then try to resolve it from the input model map. + // This will happen if a model is customized to inherit from another generated model, but that generated model + // was not also defined in custom code so Roslyn does not recognize it. + if (string.IsNullOrEmpty(baseType.Namespace)) + { + if (CodeModelGenerator.Instance.TypeFactory.InputModelTypeNameMap.TryGetValue(baseType.Name, out var baseInputModel)) { - return customBaseModel; + baseType = CodeModelGenerator.Instance.TypeFactory.CreateCSharpType(baseInputModel); } } + if (baseType != null && CodeModelGenerator.Instance.TypeFactory.CSharpTypeMap.TryGetValue( + baseType, + out var customBaseType) && + customBaseType is ModelProvider customBaseModel) + { + return customBaseModel; + } + } + if (_inputModel.BaseModel == null) + { return null; } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs index d97e46be381..069698a0283 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs @@ -1441,6 +1441,38 @@ public async Task DiscriminatorPropertyNotGeneratedIfOnCustomizedBase() Assert.AreEqual("Sample.Models", modelProvider.BaseType!.Namespace); } + [Test] + public async Task CanCustomizeBaseModelWithSpecBase() + { + var specBaseModel = InputFactory.Model( + "specBaseModel", + properties: [InputFactory.Property("specBaseProp", InputPrimitiveType.String)], + usage: InputModelTypeUsage.Json); + var customBaseModel = InputFactory.Model( + "customBaseModel", + properties: [InputFactory.Property("customBaseProp", InputPrimitiveType.String)], + usage: InputModelTypeUsage.Json); + var childModel = InputFactory.Model( + "mockInputModel", + properties: [InputFactory.Property("childProp", InputPrimitiveType.String)], + baseModel: specBaseModel, + usage: InputModelTypeUsage.Json); + + var mockGenerator = await MockHelpers.LoadMockGeneratorAsync( + inputModelTypes: [childModel, specBaseModel, customBaseModel], + compilation: async () => await Helpers.GetCompilationFromDirectoryAsync()); + + var modelProvider = mockGenerator.Object.OutputLibrary.TypeProviders.Single(t => t.Name == "MockInputModel"); + + // should have customized base type, not the spec base type + Assert.IsNotNull(modelProvider.BaseType); + Assert.IsNotNull(modelProvider.BaseTypeProvider); + Assert.AreEqual("CustomBaseModel", modelProvider.BaseType!.Name); + Assert.AreEqual("Sample.Models", modelProvider.BaseType!.Namespace); + Assert.AreEqual(1, modelProvider.BaseTypeProvider!.Properties.Count); + Assert.AreEqual("CustomBaseProp", modelProvider.BaseTypeProvider.Properties[0].Name); + } + private class NameSpaceVisitor : LibraryVisitor { protected override TypeProvider? VisitType(TypeProvider type) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CanCustomizeBaseModelWithSpecBase/MockInputModel.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CanCustomizeBaseModelWithSpecBase/MockInputModel.cs new file mode 100644 index 00000000000..44027f26c31 --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CanCustomizeBaseModelWithSpecBase/MockInputModel.cs @@ -0,0 +1,11 @@ +#nullable disable + +using Sample; +using SampleTypeSpec; + +namespace Sample.Models +{ + public partial class MockInputModel : CustomBaseModel + { + } +} From d1110c071ebdc822b669e55f0e7349a55514b139 Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Thu, 11 Dec 2025 21:47:03 +0800 Subject: [PATCH 26/40] [Specs] add case for constant query (#8836) add case to cover https://github.com/microsoft/typespec/issues/8787 --- ...on-constant-query-new-2025-9-28-11-8-13.md | 7 ++++++ packages/http-specs/spec-summary.md | 6 +++++ .../specs/parameters/query/main.tsp | 22 +++++++++++++++++++ .../specs/parameters/query/mockapi.ts | 15 +++++++++++++ 4 files changed, 50 insertions(+) create mode 100644 .chronus/changes/fix-python-constant-query-new-2025-9-28-11-8-13.md create mode 100644 packages/http-specs/specs/parameters/query/main.tsp create mode 100644 packages/http-specs/specs/parameters/query/mockapi.ts diff --git a/.chronus/changes/fix-python-constant-query-new-2025-9-28-11-8-13.md b/.chronus/changes/fix-python-constant-query-new-2025-9-28-11-8-13.md new file mode 100644 index 00000000000..8ef5e81c029 --- /dev/null +++ b/.chronus/changes/fix-python-constant-query-new-2025-9-28-11-8-13.md @@ -0,0 +1,7 @@ +--- +changeKind: feature +packages: + - "@typespec/http-specs" +--- + +Add case for constant query \ No newline at end of file diff --git a/packages/http-specs/spec-summary.md b/packages/http-specs/spec-summary.md index 70862966e7d..cb3674d16d9 100644 --- a/packages/http-specs/spec-summary.md +++ b/packages/http-specs/spec-summary.md @@ -1348,6 +1348,12 @@ Second request path: /optional/foo ``` +### Parameters_Query_Constant_post + +- Endpoint: `post /parameters/query/constant` + +Expect to handle a constant value for query and mock api returns nothing + ### Parameters_Spread_Alias_spreadAsRequestBody - Endpoint: `put /parameters/spread/alias/request-body` diff --git a/packages/http-specs/specs/parameters/query/main.tsp b/packages/http-specs/specs/parameters/query/main.tsp new file mode 100644 index 00000000000..da74b81fcbe --- /dev/null +++ b/packages/http-specs/specs/parameters/query/main.tsp @@ -0,0 +1,22 @@ +import "@typespec/http"; +import "@typespec/spector"; + +using Http; +using Spector; + +@doc("Test for query parameter cases.") +@scenarioService("/parameters/query") +namespace Parameters.Query; + +@doc("Constant query parameter verification") +@route("/constant") +interface Constant { + /** post constant query value */ + @scenario + @scenarioDoc("Expect to handle a constant value for query and mock api returns nothing") + @post + post( + @query + queryParam: "constantValue", + ): void; +} diff --git a/packages/http-specs/specs/parameters/query/mockapi.ts b/packages/http-specs/specs/parameters/query/mockapi.ts new file mode 100644 index 00000000000..262bb6cde41 --- /dev/null +++ b/packages/http-specs/specs/parameters/query/mockapi.ts @@ -0,0 +1,15 @@ +import { passOnSuccess, ScenarioMockApi } from "@typespec/spec-api"; + +export const Scenarios: Record = {}; + +Scenarios.Parameters_Query_Constant_post = passOnSuccess({ + uri: "/parameters/query/constant", + method: `post`, + request: { + query: { queryParam: "constantValue" }, + }, + response: { + status: 204, + }, + kind: "MockApiDefinition", +}); From 9aea80e4e2e9c54b659ad9a4e91295b595ce8343 Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Fri, 12 Dec 2025 00:34:54 +0800 Subject: [PATCH 27/40] [Python] fix bad indent in docstring (#8927) Fix https://teams.microsoft.com/l/message/19:b97d98e6d22c41e0970a1150b484d935@thread.skype/1762191788524?tenantId=72f988bf-86f1-41af-91ab-2d7cd011db47&groupId=3e17dcb0-4257-4a30-b843-77f47f1d4121&parentMessageId=1762191788524&teamName=Azure%20SDK&channelName=Language%20-%20Python&createdTime=1762191788524 - The indent logic is more and more complicated so we must add test case to cover related scenarios. Then I introduce local specs to cover the target docstring scenarios in this PR. - local test specs: https://github.com/Azure/autorest.python/pull/3258/files#diff-11c3177c467ef6e1428ddb7c9180ad769cf3d5596f95b4ae33c6bfb6e32b8898 and here is generated sdk docstring: https://github.com/Azure/autorest.python/pull/3258/files#diff-4ca5eea376710573c60f99fba775abf18df7302a8871df4cd74aed290e97175b **NOTE**: If Typespec author add `\n` by themselves in original docstring (e.g. [here](https://github.com/Azure/azure-rest-api-specs-pr/blob/4a11877293189d99a93774a58d2e340fc8cdf6d2/specification/ai/Azure.AI.Projects/.external-readonly/azure.openai.v1.typespec/models/responses.tsp#L17-L27)), this PR still can't resolve indent issue. But just need to give up the line break like this [commit](https://github.com/Azure/azure-rest-api-specs-pr/commit/6cecfc0d138c69a7318d1ea616773a62213d9b01), the issue of Python SDK docstring could be avoided. pending on: - [x] https://github.com/microsoft/typespec/pull/8929 --- ...ython-fix-docstring-2025-11-10-10-23-28.md | 7 +++ .../eng/scripts/ci/regenerate.ts | 6 +- .../pygen/codegen/templates/macros.jinja2 | 17 ++++-- .../generator/test/azure/requirements.txt | 1 + .../test_specs_documentation_async.py | 60 +++++++++++++++++++ .../test_specs_documentation.py | 52 ++++++++++++++++ .../generator/test/unbranded/requirements.txt | 1 + 7 files changed, 138 insertions(+), 6 deletions(-) create mode 100644 .chronus/changes/python-fix-docstring-2025-11-10-10-23-28.md create mode 100644 packages/http-client-python/generator/test/generic_mock_api_tests/asynctests/test_specs_documentation_async.py create mode 100644 packages/http-client-python/generator/test/generic_mock_api_tests/test_specs_documentation.py diff --git a/.chronus/changes/python-fix-docstring-2025-11-10-10-23-28.md b/.chronus/changes/python-fix-docstring-2025-11-10-10-23-28.md new file mode 100644 index 00000000000..6abfef34bc4 --- /dev/null +++ b/.chronus/changes/python-fix-docstring-2025-11-10-10-23-28.md @@ -0,0 +1,7 @@ +--- +changeKind: fix +packages: + - "@typespec/http-client-python" +--- + +Fix bad indent \ No newline at end of file diff --git a/packages/http-client-python/eng/scripts/ci/regenerate.ts b/packages/http-client-python/eng/scripts/ci/regenerate.ts index 5cb3c10b843..1e435969abf 100644 --- a/packages/http-client-python/eng/scripts/ci/regenerate.ts +++ b/packages/http-client-python/eng/scripts/ci/regenerate.ts @@ -22,7 +22,7 @@ const argv = parseArgs({ }); // Add this near the top with other constants -const SKIP_SPECS = ["type/union/discriminated", "documentation"]; +const SKIP_SPECS = ["type/union/discriminated"]; // Get the directory of the current file const PLUGIN_DIR = argv.values.pluginDir @@ -272,6 +272,10 @@ const EMITTER_OPTIONS: Record | Record Date: Thu, 11 Dec 2025 08:42:02 -0800 Subject: [PATCH 28/40] Fix for getting BinaryData from JsonElement (#9182) --- .../ModelSerializationExtensionsDefinition.cs | 2 +- .../MrwSerializationTypeDefinition.cs | 41 ++++++++++++------- ...lSerializationExtensionsDefinitionTests.cs | 19 +++++++++ .../MrwSerializationTypeDefinitionTests.cs | 15 +++++++ .../GetUtf8BytesIsUsedForMrwFallback.cs | 23 +++++++++++ .../Internal/ModelSerializationExtensions.cs | 18 ++++---- 6 files changed, 94 insertions(+), 24 deletions(-) create mode 100644 packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/MrwSerializationTypeDefinitionTests/GetUtf8BytesIsUsedForMrwFallback.cs diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ModelSerializationExtensionsDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ModelSerializationExtensionsDefinition.cs index 93a9bdf7d73..5a839f27088 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ModelSerializationExtensionsDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ModelSerializationExtensionsDefinition.cs @@ -157,6 +157,7 @@ protected override MethodProvider[] BuildMethods() BuildWriteNumberValueMethodProvider(), BuildWriteObjectValueMethodGeneric(), BuildWriteObjectValueMethodProvider(), + BuildGetUtf8BytesMethodProvider(), .. BuildDynamicModelHelpers() ]; } @@ -576,7 +577,6 @@ private MethodProvider[] BuildDynamicModelHelpers() [ BuildSliceToStartOfPropertyNameMethodProvider(), BuildGetFirstPropertyNameMethodProvider(), - BuildGetUtf8BytesMethodProvider(), BuildTryGetIndexMethodProvider(), BuildGetRemainderMethodProvider() ]; diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs index 0298795e5de..e3b74b65f12 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs @@ -732,7 +732,7 @@ private MethodBodyStatement[] BuildDeserializationMethodBody() // Build the deserialization statements for each property ForEachStatement deserializePropertiesForEachStatement = new("prop", _jsonElementParameterSnippet.EnumerateObject(), out var prop) { - BuildDeserializePropertiesStatements(prop.As(), _dataParameter.As()) + BuildDeserializePropertiesStatements(prop.As()) }; var valueKindEqualsNullReturn = _isStruct ? Return(Default) : Return(Null); @@ -910,7 +910,7 @@ private static ValueExpression GetValueForSerializationConstructor(PropertyProvi return propertyProvider.AsVariableExpression; } - private List BuildDeserializePropertiesStatements(ScopedApi jsonProperty, ScopedApi data) + private List BuildDeserializePropertiesStatements(ScopedApi jsonProperty) { List propertyDeserializationStatements = []; Dictionary> additionalPropsValueKindBodyStatements = []; @@ -943,7 +943,7 @@ private List BuildDeserializePropertiesStatements(ScopedApi // handle additional properties if (parameter.Property != null && parameter.Property != _additionalBinaryDataProperty.Value && parameter.Property.IsAdditionalProperties) { - AddAdditionalPropertiesValueKindStatements(additionalPropsValueKindBodyStatements, parameter.Property, jsonProperty, data); + AddAdditionalPropertiesValueKindStatements(additionalPropsValueKindBodyStatements, parameter.Property, jsonProperty); continue; } @@ -951,7 +951,7 @@ private List BuildDeserializePropertiesStatements(ScopedApi // By default, we should only deserialize properties with wire info that are payload properties. // Those properties without wire info indicate they are not spec properties. - if (wireInfo == null || wireInfo.IsHttpMetadata == true) + if (wireInfo == null || wireInfo.IsHttpMetadata) { continue; } @@ -998,7 +998,7 @@ private List BuildDeserializePropertiesStatements(ScopedApi if (_additionalBinaryDataProperty.Value != null) { var binaryDataDeserializationValue = ScmCodeModelGenerator.Instance.TypeFactory.DeserializeJsonValue( - _additionalBinaryDataProperty.Value.Type.ElementType.FrameworkType, jsonProperty.Value(), _dataParameter.As(), _mrwOptionsParameterSnippet, SerializationFormat.Default); + _additionalBinaryDataProperty.Value.Type.ElementType, jsonProperty.Value(), _dataParameter.As(), _mrwOptionsParameterSnippet, SerializationFormat.Default); propertyDeserializationStatements.Add( _additionalBinaryDataProperty.Value.AsVariableExpression.AsDictionary(_additionalBinaryDataProperty.Value.Type).Add(jsonProperty.Name(), binaryDataDeserializationValue)); } @@ -1028,8 +1028,7 @@ private List BuildDeserializePropertiesStatements(ScopedApi private void AddAdditionalPropertiesValueKindStatements( Dictionary> additionalPropsValueKindBodyStatements, PropertyProvider additionalPropertiesProperty, - ScopedApi jsonProperty, - ScopedApi data) + ScopedApi jsonProperty) { DictionaryExpression additionalPropsDict = additionalPropertiesProperty.AsVariableExpression.AsDictionary(additionalPropertiesProperty.Type); var valueType = additionalPropertiesProperty.Type.ElementType; @@ -1424,22 +1423,36 @@ private MethodBodyStatement DeserializeValue( } else { - value = CreateDeserializeValueExpression(valueType, serializationFormat, jsonElement, jsonElement.GetUtf8Bytes()); + value = CreateDeserializeValueExpression(valueType, serializationFormat, jsonElement); return MethodBodyStatement.Empty; } } - private ValueExpression CreateDeserializeValueExpression(CSharpType valueType, SerializationFormat serializationFormat, ScopedApi jsonElement, ScopedApi data) => - valueType switch + private ValueExpression CreateDeserializeValueExpression( + CSharpType valueType, + SerializationFormat serializationFormat, + ScopedApi jsonElement) + { + var data = jsonElement.GetUtf8Bytes(); + + return valueType switch { { IsFrameworkType: true } when valueType.FrameworkType == typeof(Nullable<>) => - ScmCodeModelGenerator.Instance.TypeFactory.DeserializeJsonValue(valueType.Arguments[0].FrameworkType, jsonElement, _dataParameter.As(), _mrwOptionsParameterSnippet, serializationFormat), + ScmCodeModelGenerator.Instance.TypeFactory.DeserializeJsonValue( + valueType.Arguments[0].FrameworkType, jsonElement, data, + _mrwOptionsParameterSnippet, serializationFormat), { IsFrameworkType: true } => - ScmCodeModelGenerator.Instance.TypeFactory.DeserializeJsonValue(valueType.FrameworkType, jsonElement, _dataParameter.As(), _mrwOptionsParameterSnippet, serializationFormat), + ScmCodeModelGenerator.Instance.TypeFactory.DeserializeJsonValue(valueType.FrameworkType, + jsonElement, data, _mrwOptionsParameterSnippet, + serializationFormat), { IsEnum: true } => - valueType.ToEnum(ScmCodeModelGenerator.Instance.TypeFactory.DeserializeJsonValue(valueType.UnderlyingEnumType!, jsonElement, _dataParameter.As(), _mrwOptionsParameterSnippet, serializationFormat)), - _ => GetDeserializationMethodInvocationForType(valueType, jsonElement, data, _mrwOptionsParameterSnippet) + valueType.ToEnum(ScmCodeModelGenerator.Instance.TypeFactory.DeserializeJsonValue( + valueType.UnderlyingEnumType!, jsonElement, data, + _mrwOptionsParameterSnippet, serializationFormat)), + _ => GetDeserializationMethodInvocationForType(valueType, jsonElement, data, + _mrwOptionsParameterSnippet) }; + } private MethodBodyStatement CreateDeserializeDictionaryValueStatement( CSharpType dictionaryItemType, diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/Definitions/ModelSerializationExtensionsDefinitionTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/Definitions/ModelSerializationExtensionsDefinitionTests.cs index 3575f184e97..a9e2b5677a3 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/Definitions/ModelSerializationExtensionsDefinitionTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/Definitions/ModelSerializationExtensionsDefinitionTests.cs @@ -202,6 +202,25 @@ public void ValidateGetRequiredStringMethodIsGenerated() Assert.AreEqual(typeof(JsonElement), getRequiredStringMethod.Signature.Parameters[0].Type.FrameworkType); } + [Test] + public void ValidateGetUtf8BytesMethodIsGenerated() + { + MockHelpers.LoadMockGenerator(); + + var definition = new ModelSerializationExtensionsDefinition(); + var methods = definition.Methods; + + Assert.IsNotNull(methods); + var getUtf8BytesMethod = methods.SingleOrDefault(m => m.Signature.Name == "GetUtf8Bytes"); + Assert.IsNotNull(getUtf8BytesMethod, "GetUtf8Bytes method should be generated"); + Assert.AreEqual(typeof(BinaryData), getUtf8BytesMethod!.Signature.ReturnType?.FrameworkType); + Assert.IsTrue(getUtf8BytesMethod.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Public)); + Assert.IsTrue(getUtf8BytesMethod.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Static)); + Assert.IsTrue(getUtf8BytesMethod.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Extension)); + Assert.AreEqual(1, getUtf8BytesMethod.Signature.Parameters.Count); + Assert.AreEqual(typeof(JsonElement), getUtf8BytesMethod.Signature.Parameters[0].Type.FrameworkType); + } + [Test] public void ValidateWriteStringValueMethodsAreGenerated() { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/MrwSerializationTypeDefinitionTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/MrwSerializationTypeDefinitionTests.cs index 621f52b1671..d857b8162d3 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/MrwSerializationTypeDefinitionTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/MrwSerializationTypeDefinitionTests.cs @@ -598,6 +598,21 @@ public void SerializedNameIsUsed(bool isRequired) Assert.AreEqual(Helpers.GetExpectedFromFile(isRequired.ToString()), methodBody); } + [Test] + public void GetUtf8BytesIsUsedForMrwFallback() + { + var property = InputFactory.Property( + "mockProperty", + InputFactory.Model("SomeExternalModel", external: new InputExternalTypeMetadata("System.IO.File", null, null))); + + var inputModel = InputFactory.Model("mockInputModel", properties: [property]); + var (_, serialization) = CreateModelAndSerialization(inputModel); + + var deserializationMethod = serialization.Methods.Single(m => m.Signature.Name.StartsWith("Deserialize")); + var methodBody = deserializationMethod.BodyStatements!.ToDisplayString(); + Assert.AreEqual(Helpers.GetExpectedFromFile(), methodBody); + } + [Test] public void TestBuildDeserializationMethodNestedSARD() { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/MrwSerializationTypeDefinitionTests/GetUtf8BytesIsUsedForMrwFallback.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/MrwSerializationTypeDefinitionTests/GetUtf8BytesIsUsedForMrwFallback.cs new file mode 100644 index 00000000000..0cd6864f675 --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/MrwSerializationTypeDefinitionTests/GetUtf8BytesIsUsedForMrwFallback.cs @@ -0,0 +1,23 @@ +if ((element.ValueKind == global::System.Text.Json.JsonValueKind.Null)) +{ + return null; +} +global::System.IO.File mockProperty = default; +global::System.Collections.Generic.IDictionary additionalBinaryDataProperties = new global::Sample.ChangeTrackingDictionary(); +foreach (var prop in element.EnumerateObject()) +{ + if (prop.NameEquals("mockProperty"u8)) + { + if ((prop.Value.ValueKind == global::System.Text.Json.JsonValueKind.Null)) + { + continue; + } + mockProperty = global::System.ClientModel.Primitives.ModelReaderWriter.Read(prop.Value.GetUtf8Bytes(), global::Sample.ModelSerializationExtensions.WireOptions, global::Sample.SampleContext.Default); + continue; + } + if ((options.Format != "W")) + { + additionalBinaryDataProperties.Add(prop.Name, global::System.BinaryData.FromString(prop.Value.GetRawText())); + } +} +return new global::Sample.Models.MockInputModel(mockProperty, additionalBinaryDataProperties); diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Internal/ModelSerializationExtensions.cs b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Internal/ModelSerializationExtensions.cs index 25a919caece..099511239df 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Internal/ModelSerializationExtensions.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Internal/ModelSerializationExtensions.cs @@ -258,6 +258,15 @@ public static void WriteObjectValue(this Utf8JsonWriter writer, object value, Mo writer.WriteObjectValue(value, options); } + public static BinaryData GetUtf8Bytes(this JsonElement element) + { +#if NET9_0_OR_GREATER + return new global::System.BinaryData(global::System.Runtime.InteropServices.JsonMarshal.GetRawUtf8Value(element).ToArray()); +#else + return BinaryData.FromString(element.GetRawText()); +#endif + } + public static ReadOnlySpan SliceToStartOfPropertyName(this ReadOnlySpan jsonPath) { ReadOnlySpan local = jsonPath; @@ -304,15 +313,6 @@ public static string GetFirstPropertyName(this ReadOnlySpan jsonPath, out return key; } - public static BinaryData GetUtf8Bytes(this JsonElement element) - { -#if NET9_0_OR_GREATER - return new global::System.BinaryData(global::System.Runtime.InteropServices.JsonMarshal.GetRawUtf8Value(element).ToArray()); -#else - return BinaryData.FromString(element.GetRawText()); -#endif - } - public static bool TryGetIndex(this ReadOnlySpan indexSlice, out int index, out int bytesConsumed) { index = -1; From d2bd68e844444049a0deee2d2edb5537574eeb33 Mon Sep 17 00:00:00 2001 From: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com> Date: Thu, 11 Dec 2025 12:20:52 -0800 Subject: [PATCH 29/40] Always pass CSharpType to DeserializeJsonValue (#9191) --- .../src/Providers/MrwSerializationTypeDefinition.cs | 4 ++-- .../src/Providers/ScmMethodProviderCollection.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs index e3b74b65f12..fb1c487ca70 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs @@ -1439,10 +1439,10 @@ private ValueExpression CreateDeserializeValueExpression( { { IsFrameworkType: true } when valueType.FrameworkType == typeof(Nullable<>) => ScmCodeModelGenerator.Instance.TypeFactory.DeserializeJsonValue( - valueType.Arguments[0].FrameworkType, jsonElement, data, + valueType.Arguments[0], jsonElement, data, _mrwOptionsParameterSnippet, serializationFormat), { IsFrameworkType: true } => - ScmCodeModelGenerator.Instance.TypeFactory.DeserializeJsonValue(valueType.FrameworkType, + ScmCodeModelGenerator.Instance.TypeFactory.DeserializeJsonValue(valueType, jsonElement, data, _mrwOptionsParameterSnippet, serializationFormat), { IsEnum: true } => diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ScmMethodProviderCollection.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ScmMethodProviderCollection.cs index 7089a0d2e4a..22f202f9210 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ScmMethodProviderCollection.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ScmMethodProviderCollection.cs @@ -150,7 +150,7 @@ .. GetStackVariablesForReturnValueConversion(result, responseBodyType, isAsync, Declare("element", jsonDocument.RootElement(), out var jsonElement), Return(result.FromValue( ScmCodeModelGenerator.Instance.TypeFactory.DeserializeJsonValue( - responseBodyType.FrameworkType, + responseBodyType, jsonElement, data, ScmCodeModelGenerator.Instance.ModelSerializationExtensionsDefinition.WireOptionsField.As(), From b3e4cdb46e089010b4e80a6fc5f6e5c422c8ac2b Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Thu, 11 Dec 2025 18:00:20 -0600 Subject: [PATCH 30/40] Upgrade @typespec/compiler and related libraries to latest versions in http-client-csharp (#9179) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Upgrade TypeSpec compiler and related libraries to latest versions - [x] Update `@typespec/http-client-csharp` package.json dependencies - [x] Upgrade `@typespec/compiler` from ^1.6.0 to ^1.7.0 (peerDependencies and devDependencies) - [x] Upgrade `@typespec/http` from ^1.6.0 to ^1.7.0 (peerDependencies and devDependencies) - [x] Upgrade `@typespec/openapi` from ^1.6.0 to ^1.7.0 (peerDependencies and devDependencies) - [x] Upgrade `@typespec/json-schema` from 1.6.0 to 1.7.0 (devDependencies) - [x] Upgrade `@typespec/rest` from 0.76.0 to 0.77.0 (peerDependencies and devDependencies) - [x] Upgrade `@typespec/streams` from 0.76.0 to 0.77.0 (peerDependencies and devDependencies) - [x] Upgrade `@typespec/versioning` from 0.76.0 to 0.77.0 (peerDependencies and devDependencies) - [x] Upgrade `@typespec/xml` from 0.76.0 to 0.77.0 (devDependencies) - [x] Upgrade `@typespec/library-linter` from 0.76.0 to 0.77.0 (devDependencies) - [x] Upgrade `@azure-tools/typespec-client-generator-core` from 0.62.0 to 0.63.0 (devDependencies) - [x] Upgrade `@azure-tools/typespec-client-generator-core` peerDependency from `>=0.62.0 < 0.63.0 || ~0.63.0-0` to `>=0.63.0 < 0.64.0 || ~0.64.0-0` (following existing pattern) - [x] Upgrade `@azure-tools/azure-http-specs` from 0.1.0-alpha.32 to 0.1.0-alpha.33 (devDependencies) - [x] Run `npm install --legacy-peer-deps` in http-client-csharp to update package-lock.json - [x] Verify http-specs uses workspace dependencies (confirmed: uses `workspace:^` for all TypeSpec packages, automatically resolves to latest versions) - [x] Verify no breaking changes in upgraded versions (confirmed: all updates are non-breaking, mostly dependency bumps and minor features) ### Summary Successfully upgraded http-client-csharp to use the latest TypeSpec compiler (1.7.0) and related libraries (0.77.0 for rest/versioning/streams/xml), and upgraded @azure-tools packages to their latest versions (client-generator-core 0.63.0 and azure-http-specs 0.1.0-alpha.33). All version ranges follow the existing pattern used in the package. All version upgrades are non-breaking changes.
Original prompt > > ---- > > *This section details on the original issue you should resolve* > > Upgrade to latest compiler version > typesspec/compiler and all related libraries. > > ## Comments on the Issue (you are @copilot in this section) > > > >
- Fixes microsoft/typespec#9178 --- ✨ Let Copilot coding agent [set things up for you](https://github.com/microsoft/typespec/issues/new?title=✨+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot) — coding agent works faster and does higher quality work when set up for your repo. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com> Co-authored-by: jolov --- .../src/Properties/launchSettings.json | 10 + .../http/documentation/Configuration.json | 3 + .../http/documentation/Documentation.sln | 48 + .../documentation/src/Documentation.csproj | 15 + .../src/Generated/DocumentationClient.cs | 24 + .../Generated/DocumentationClientOptions.cs | 12 + .../Generated/DocumentationModelFactory.cs | 13 + .../http/documentation/src/Generated/Lists.cs | 42 + .../src/Generated/Models/BulletPointsEnum.cs | 28 + .../Models/BulletPointsModel.Serialization.cs | 33 + .../src/Generated/Models/BulletPointsModel.cs | 13 + .../Generated/Models/DocumentationContext.cs | 14 + .../src/Generated/TextFormatting.cs | 42 + .../http/documentation/tspCodeModel.json | 605 ++++++ .../http/encode/array/Configuration.json | 3 + .../http/encode/array/Encode.Array.sln | 48 + .../http/encode/array/src/Encode.Array.csproj | 15 + .../encode/array/src/Generated/ArrayClient.cs | 21 + .../array/src/Generated/ArrayClientOptions.cs | 12 + .../src/Generated/EncodeArrayModelFactory.cs | 19 + ...mmaDelimitedArrayProperty.Serialization.cs | 38 + .../Models/CommaDelimitedArrayProperty.cs | 15 + .../Generated/Models/Encode_ArrayContext.cs | 16 + ...ineDelimitedArrayProperty.Serialization.cs | 38 + .../Models/NewlineDelimitedArrayProperty.cs | 15 + ...ipeDelimitedArrayProperty.Serialization.cs | 38 + .../Models/PipeDelimitedArrayProperty.cs | 15 + ...aceDelimitedArrayProperty.Serialization.cs | 38 + .../Models/SpaceDelimitedArrayProperty.cs | 15 + .../encode/array/src/Generated/Property.cs | 51 + .../http/encode/array/tspCodeModel.json | 995 ++++++++++ .../src/Generated/ModelProperties.cs | 8 + .../Models/DictMethods.Serialization.cs | 36 + .../src/Generated/Models/DictMethods.cs | 31 + .../Generated/Models/SpecialWordsContext.cs | 1 + .../src/Generated/SpecialWordsModelFactory.cs | 2 + .../http/special-words/tspCodeModel.json | 1726 ++++++++++------- packages/http-client-csharp/package-lock.json | 1160 ++++++----- packages/http-client-csharp/package.json | 38 +- 39 files changed, 4147 insertions(+), 1149 deletions(-) create mode 100644 packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/Configuration.json create mode 100644 packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/Documentation.sln create mode 100644 packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Documentation.csproj create mode 100644 packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Generated/DocumentationClient.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Generated/DocumentationClientOptions.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Generated/DocumentationModelFactory.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Generated/Lists.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Generated/Models/BulletPointsEnum.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Generated/Models/BulletPointsModel.Serialization.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Generated/Models/BulletPointsModel.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Generated/Models/DocumentationContext.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Generated/TextFormatting.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/tspCodeModel.json create mode 100644 packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/Configuration.json create mode 100644 packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/Encode.Array.sln create mode 100644 packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Encode.Array.csproj create mode 100644 packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/ArrayClient.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/ArrayClientOptions.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/EncodeArrayModelFactory.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Models/CommaDelimitedArrayProperty.Serialization.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Models/CommaDelimitedArrayProperty.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Models/Encode_ArrayContext.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Models/NewlineDelimitedArrayProperty.Serialization.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Models/NewlineDelimitedArrayProperty.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Models/PipeDelimitedArrayProperty.Serialization.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Models/PipeDelimitedArrayProperty.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Models/SpaceDelimitedArrayProperty.Serialization.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Models/SpaceDelimitedArrayProperty.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Property.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/tspCodeModel.json create mode 100644 packages/http-client-csharp/generator/TestProjects/Spector/http/special-words/src/Generated/Models/DictMethods.Serialization.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Spector/http/special-words/src/Generated/Models/DictMethods.cs diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Properties/launchSettings.json b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Properties/launchSettings.json index dadca87bd7f..744f37906d1 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Properties/launchSettings.json +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Properties/launchSettings.json @@ -45,6 +45,16 @@ "commandName": "Executable", "executablePath": "$(SolutionDir)/../dist/generator/Microsoft.TypeSpec.Generator.exe" }, + "http-documentation": { + "commandLineArgs": "$(SolutionDir)/TestProjects/Spector/http/documentation -g StubLibraryGenerator", + "commandName": "Executable", + "executablePath": "$(SolutionDir)/../dist/generator/Microsoft.TypeSpec.Generator.exe" + }, + "http-encode-array": { + "commandLineArgs": "$(SolutionDir)/TestProjects/Spector/http/encode/array -g StubLibraryGenerator", + "commandName": "Executable", + "executablePath": "$(SolutionDir)/../dist/generator/Microsoft.TypeSpec.Generator.exe" + }, "http-encode-bytes": { "commandLineArgs": "$(SolutionDir)/TestProjects/Spector/http/encode/bytes -g StubLibraryGenerator", "commandName": "Executable", diff --git a/packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/Configuration.json b/packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/Configuration.json new file mode 100644 index 00000000000..3335831568c --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/Configuration.json @@ -0,0 +1,3 @@ +{ + "package-name": "Documentation" +} diff --git a/packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/Documentation.sln b/packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/Documentation.sln new file mode 100644 index 00000000000..a0b3f32bbb2 --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/Documentation.sln @@ -0,0 +1,48 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Documentation", "src\Documentation.csproj", "{28FF4005-4467-4E36-92E7-DEA27DEB1519}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B0C276D1-2930-4887-B29A-D1A33E7009A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B0C276D1-2930-4887-B29A-D1A33E7009A2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B0C276D1-2930-4887-B29A-D1A33E7009A2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B0C276D1-2930-4887-B29A-D1A33E7009A2}.Release|Any CPU.Build.0 = Release|Any CPU + {8E9A77AC-792A-4432-8320-ACFD46730401}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8E9A77AC-792A-4432-8320-ACFD46730401}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8E9A77AC-792A-4432-8320-ACFD46730401}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8E9A77AC-792A-4432-8320-ACFD46730401}.Release|Any CPU.Build.0 = Release|Any CPU + {A4241C1F-A53D-474C-9E4E-075054407E74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A4241C1F-A53D-474C-9E4E-075054407E74}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A4241C1F-A53D-474C-9E4E-075054407E74}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A4241C1F-A53D-474C-9E4E-075054407E74}.Release|Any CPU.Build.0 = Release|Any CPU + {FA8BD3F1-8616-47B6-974C-7576CDF4717E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FA8BD3F1-8616-47B6-974C-7576CDF4717E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FA8BD3F1-8616-47B6-974C-7576CDF4717E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FA8BD3F1-8616-47B6-974C-7576CDF4717E}.Release|Any CPU.Build.0 = Release|Any CPU + {85677AD3-C214-42FA-AE6E-49B956CAC8DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {85677AD3-C214-42FA-AE6E-49B956CAC8DC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {85677AD3-C214-42FA-AE6E-49B956CAC8DC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {85677AD3-C214-42FA-AE6E-49B956CAC8DC}.Release|Any CPU.Build.0 = Release|Any CPU + {28FF4005-4467-4E36-92E7-DEA27DEB1519}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {28FF4005-4467-4E36-92E7-DEA27DEB1519}.Debug|Any CPU.Build.0 = Debug|Any CPU + {28FF4005-4467-4E36-92E7-DEA27DEB1519}.Release|Any CPU.ActiveCfg = Release|Any CPU + {28FF4005-4467-4E36-92E7-DEA27DEB1519}.Release|Any CPU.Build.0 = Release|Any CPU + {1F1CD1D4-9932-4B73-99D8-C252A67D4B46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1F1CD1D4-9932-4B73-99D8-C252A67D4B46}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1F1CD1D4-9932-4B73-99D8-C252A67D4B46}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1F1CD1D4-9932-4B73-99D8-C252A67D4B46}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {A97F4B90-2591-4689-B1F8-5F21FE6D6CAE} + EndGlobalSection +EndGlobal diff --git a/packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Documentation.csproj b/packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Documentation.csproj new file mode 100644 index 00000000000..453321f4b91 --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Documentation.csproj @@ -0,0 +1,15 @@ + + + This is the Documentation client library for developing .NET applications with rich experience. + SDK Code Generation Documentation + 1.0.0-beta.1 + Documentation + netstandard2.0;net8.0 + latest + true + + + + + + diff --git a/packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Generated/DocumentationClient.cs b/packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Generated/DocumentationClient.cs new file mode 100644 index 00000000000..8f961dff791 --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Generated/DocumentationClient.cs @@ -0,0 +1,24 @@ +// + +#nullable disable + +using System; +using System.ClientModel.Primitives; +using Documentation._Lists; +using Documentation._TextFormatting; + +namespace Documentation +{ + public partial class DocumentationClient + { + public DocumentationClient() : this(new Uri("http://localhost:3000"), new DocumentationClientOptions()) => throw null; + + public DocumentationClient(Uri endpoint, DocumentationClientOptions options) => throw null; + + public ClientPipeline Pipeline => throw null; + + public virtual Lists GetListsClient() => throw null; + + public virtual TextFormatting GetTextFormattingClient() => throw null; + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Generated/DocumentationClientOptions.cs b/packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Generated/DocumentationClientOptions.cs new file mode 100644 index 00000000000..d14497f2a3d --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Generated/DocumentationClientOptions.cs @@ -0,0 +1,12 @@ +// + +#nullable disable + +using System.ClientModel.Primitives; + +namespace Documentation +{ + public partial class DocumentationClientOptions : ClientPipelineOptions + { + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Generated/DocumentationModelFactory.cs b/packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Generated/DocumentationModelFactory.cs new file mode 100644 index 00000000000..4440dc1b6a0 --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Generated/DocumentationModelFactory.cs @@ -0,0 +1,13 @@ +// + +#nullable disable + +using Documentation._Lists; + +namespace Documentation +{ + public static partial class DocumentationModelFactory + { + public static BulletPointsModel BulletPointsModel(BulletPointsEnum prop = default) => throw null; + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Generated/Lists.cs b/packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Generated/Lists.cs new file mode 100644 index 00000000000..34bf1c4e427 --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Generated/Lists.cs @@ -0,0 +1,42 @@ +// + +#nullable disable + +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Threading; +using System.Threading.Tasks; + +namespace Documentation._Lists +{ + public partial class Lists + { + protected Lists() => throw null; + + public ClientPipeline Pipeline => throw null; + + public virtual ClientResult BulletPointsOp(RequestOptions options) => throw null; + + public virtual Task BulletPointsOpAsync(RequestOptions options) => throw null; + + public virtual ClientResult BulletPointsOp(CancellationToken cancellationToken = default) => throw null; + + public virtual Task BulletPointsOpAsync(CancellationToken cancellationToken = default) => throw null; + + public virtual ClientResult BulletPointsModel(BinaryContent content, RequestOptions options = null) => throw null; + + public virtual Task BulletPointsModelAsync(BinaryContent content, RequestOptions options = null) => throw null; + + public virtual ClientResult BulletPointsModel(BulletPointsModel input, CancellationToken cancellationToken = default) => throw null; + + public virtual Task BulletPointsModelAsync(BulletPointsModel input, CancellationToken cancellationToken = default) => throw null; + + public virtual ClientResult Numbered(RequestOptions options) => throw null; + + public virtual Task NumberedAsync(RequestOptions options) => throw null; + + public virtual ClientResult Numbered(CancellationToken cancellationToken = default) => throw null; + + public virtual Task NumberedAsync(CancellationToken cancellationToken = default) => throw null; + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Generated/Models/BulletPointsEnum.cs b/packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Generated/Models/BulletPointsEnum.cs new file mode 100644 index 00000000000..1487e435c2e --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Generated/Models/BulletPointsEnum.cs @@ -0,0 +1,28 @@ +// + +#nullable disable + +namespace Documentation._Lists +{ + public enum BulletPointsEnum + { + /// + /// Simple bullet point. This line is intentionally long to test text wrapping in bullet points within enum documentation comments. It should properly indent the wrapped lines. + /// - One: one. This line is intentionally long to test text wrapping in bullet points within enum documentation comments. It should properly indent the wrapped lines. + /// - Two: two. This line is intentionally long to test text wrapping in bullet points within enum documentation comments. It should properly indent the wrapped lines. + /// + Simple, + /// + /// Bullet point with **bold text**. This line is intentionally long to test text wrapping in bullet points within enum documentation comments. It should properly indent the wrapped lines. + /// - **One**: one. This line is intentionally long to test text wrapping in bullet points within enum documentation comments. It should properly indent the wrapped lines. + /// - **Two**: two. This line is intentionally long to test text wrapping in bullet points within enum documentation comments. It should properly indent the wrapped lines. + /// + Bold, + /// + /// Bullet point with *italic text*. This line is intentionally long to test text wrapping in bullet points within enum documentation comments. It should properly indent the wrapped lines. + /// - *One*: one. This line is intentionally long to test text wrapping in bullet points within enum documentation comments. It should properly indent the wrapped lines. + /// - *Two*: two. This line is intentionally long to test text wrapping in bullet points within enum documentation comments. It should properly indent the wrapped lines. + /// + Italic + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Generated/Models/BulletPointsModel.Serialization.cs b/packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Generated/Models/BulletPointsModel.Serialization.cs new file mode 100644 index 00000000000..0648f46131f --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Generated/Models/BulletPointsModel.Serialization.cs @@ -0,0 +1,33 @@ +// + +#nullable disable + +using System; +using System.ClientModel.Primitives; +using System.Text.Json; + +namespace Documentation._Lists +{ + public partial class BulletPointsModel : IJsonModel + { + internal BulletPointsModel() => throw null; + + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) => throw null; + + protected virtual void JsonModelWriteCore(Utf8JsonWriter writer, ModelReaderWriterOptions options) => throw null; + + BulletPointsModel IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) => throw null; + + protected virtual BulletPointsModel JsonModelCreateCore(ref Utf8JsonReader reader, ModelReaderWriterOptions options) => throw null; + + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) => throw null; + + protected virtual BinaryData PersistableModelWriteCore(ModelReaderWriterOptions options) => throw null; + + BulletPointsModel IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) => throw null; + + protected virtual BulletPointsModel PersistableModelCreateCore(BinaryData data, ModelReaderWriterOptions options) => throw null; + + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => throw null; + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Generated/Models/BulletPointsModel.cs b/packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Generated/Models/BulletPointsModel.cs new file mode 100644 index 00000000000..e4a1b38cc2e --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Generated/Models/BulletPointsModel.cs @@ -0,0 +1,13 @@ +// + +#nullable disable + +namespace Documentation._Lists +{ + public partial class BulletPointsModel + { + public BulletPointsModel(BulletPointsEnum prop) => throw null; + + public BulletPointsEnum Prop => throw null; + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Generated/Models/DocumentationContext.cs b/packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Generated/Models/DocumentationContext.cs new file mode 100644 index 00000000000..87061329c79 --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Generated/Models/DocumentationContext.cs @@ -0,0 +1,14 @@ +// + +#nullable disable + +using System.ClientModel.Primitives; +using Documentation._Lists; + +namespace Documentation +{ + [ModelReaderWriterBuildable(typeof(BulletPointsModel))] + public partial class DocumentationContext : ModelReaderWriterContext + { + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Generated/TextFormatting.cs b/packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Generated/TextFormatting.cs new file mode 100644 index 00000000000..6fb8a1e8646 --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/src/Generated/TextFormatting.cs @@ -0,0 +1,42 @@ +// + +#nullable disable + +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Threading; +using System.Threading.Tasks; + +namespace Documentation._TextFormatting +{ + public partial class TextFormatting + { + protected TextFormatting() => throw null; + + public ClientPipeline Pipeline => throw null; + + public virtual ClientResult BoldText(RequestOptions options) => throw null; + + public virtual Task BoldTextAsync(RequestOptions options) => throw null; + + public virtual ClientResult BoldText(CancellationToken cancellationToken = default) => throw null; + + public virtual Task BoldTextAsync(CancellationToken cancellationToken = default) => throw null; + + public virtual ClientResult ItalicText(RequestOptions options) => throw null; + + public virtual Task ItalicTextAsync(RequestOptions options) => throw null; + + public virtual ClientResult ItalicText(CancellationToken cancellationToken = default) => throw null; + + public virtual Task ItalicTextAsync(CancellationToken cancellationToken = default) => throw null; + + public virtual ClientResult CombinedFormatting(RequestOptions options) => throw null; + + public virtual Task CombinedFormattingAsync(RequestOptions options) => throw null; + + public virtual ClientResult CombinedFormatting(CancellationToken cancellationToken = default) => throw null; + + public virtual Task CombinedFormattingAsync(CancellationToken cancellationToken = default) => throw null; + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/tspCodeModel.json b/packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/tspCodeModel.json new file mode 100644 index 00000000000..ce8641158ff --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Spector/http/documentation/tspCodeModel.json @@ -0,0 +1,605 @@ +{ + "name": "Documentation", + "apiVersions": [], + "enums": [ + { + "$id": "1", + "kind": "enum", + "name": "BulletPointsEnum", + "crossLanguageDefinitionId": "Documentation.Lists.BulletPointsEnum", + "valueType": { + "$id": "2", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "values": [ + { + "$id": "3", + "kind": "enumvalue", + "name": "Simple", + "value": "Simple", + "valueType": { + "$ref": "2" + }, + "enumType": { + "$ref": "1" + }, + "doc": "Simple bullet point. This line is intentionally long to test text wrapping in bullet points within enum documentation comments. It should properly indent the wrapped lines.\n- One: one. This line is intentionally long to test text wrapping in bullet points within enum documentation comments. It should properly indent the wrapped lines.\n- Two: two. This line is intentionally long to test text wrapping in bullet points within enum documentation comments. It should properly indent the wrapped lines.", + "decorators": [] + }, + { + "$id": "4", + "kind": "enumvalue", + "name": "Bold", + "value": "Bold", + "valueType": { + "$ref": "2" + }, + "enumType": { + "$ref": "1" + }, + "doc": "Bullet point with **bold text**. This line is intentionally long to test text wrapping in bullet points within enum documentation comments. It should properly indent the wrapped lines.\n- **One**: one. This line is intentionally long to test text wrapping in bullet points within enum documentation comments. It should properly indent the wrapped lines.\n- **Two**: two. This line is intentionally long to test text wrapping in bullet points within enum documentation comments. It should properly indent the wrapped lines.", + "decorators": [] + }, + { + "$id": "5", + "kind": "enumvalue", + "name": "Italic", + "value": "Italic", + "valueType": { + "$ref": "2" + }, + "enumType": { + "$ref": "1" + }, + "doc": "Bullet point with *italic text*. This line is intentionally long to test text wrapping in bullet points within enum documentation comments. It should properly indent the wrapped lines.\n- *One*: one. This line is intentionally long to test text wrapping in bullet points within enum documentation comments. It should properly indent the wrapped lines.\n- *Two*: two. This line is intentionally long to test text wrapping in bullet points within enum documentation comments. It should properly indent the wrapped lines.", + "decorators": [] + } + ], + "namespace": "Documentation.Lists", + "doc": "This tests really long bullet points in enum documentation to see how wrapping and formatting are handled. This should wrap around correctly and maintain proper indentation for each line.\n- Simple bullet point. This bullet point is going to be very long to test how text wrapping is handled in bullet points within documentation comments. It should properly indent the wrapped lines.\n- Another bullet point with **bold text**. This bullet point is also intentionally long to see how the formatting is preserved when the text wraps onto multiple lines in the generated documentation.\n- Third bullet point with *italic text*. Similar to the previous points, this one is extended to ensure that the wrapping and formatting are correctly applied in the output.\n- Complex bullet point with **bold** and *italic* combined. This bullet point combines both bold and italic formatting and is long enough to test the wrapping behavior in such cases.\n- **Bold bullet point**: A bullet point that is entirely bolded. This point is also made lengthy to observe how the bold formatting is maintained across wrapped lines.\n- *Italic bullet point*: A bullet point that is entirely italicized. This final point is extended to verify that italic formatting is correctly applied even when the text spans multiple lines.", + "isFixed": true, + "isFlags": false, + "usage": "Input,Json", + "decorators": [] + } + ], + "constants": [ + { + "$id": "6", + "kind": "constant", + "name": "bulletPointsModelContentType", + "namespace": "", + "usage": "None", + "valueType": { + "$id": "7", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "value": "application/json", + "decorators": [] + } + ], + "models": [ + { + "$id": "8", + "kind": "model", + "name": "BulletPointsModel", + "namespace": "Documentation.Lists", + "crossLanguageDefinitionId": "Documentation.Lists.BulletPointsModel", + "usage": "Input,Json", + "doc": "This tests:\n- Simple bullet point. This bullet point is going to be very long to test how text wrapping is handled in bullet points within documentation comments. It should properly indent the wrapped lines.\n- Another bullet point with **bold text**. This bullet point is also intentionally long to see how the formatting is preserved when the text wraps onto multiple lines in the generated documentation.\n- Third bullet point with *italic text*. Similar to the previous points, this one is extended to ensure that the wrapping and formatting are correctly applied in the output.\n- Complex bullet point with **bold** and *italic* combined. This bullet point combines both bold and italic formatting and is long enough to test the wrapping behavior in such cases.\n- **Bold bullet point**: A bullet point that is entirely bolded. This point is also made lengthy to observe how the bold formatting is maintained across wrapped lines.\n- *Italic bullet point*: A bullet point that is entirely italicized. This final point is extended to verify that italic formatting is correctly applied even when the text spans multiple lines.", + "decorators": [], + "properties": [ + { + "$id": "9", + "kind": "property", + "name": "prop", + "serializedName": "prop", + "doc": "This property uses an enum with bullet point documentation. The enum documentation includes various formatting styles to test rendering. The styles are:\n- Simple bullet point. This bullet point is going to be very long to test how text wrapping is handled in bullet points within documentation comments. It should properly indent the wrapped lines.\n- Bullet point with **bold text**. This bullet point is also intentionally long to see how the formatting is preserved when the text wraps onto multiple\n- Bullet point with *italic text*. Similar to the previous points, this one is extended to ensure that the wrapping and formatting are correctly applied in the output.\n- Complex bullet point with **bold** and *italic* combined. This bullet point combines both bold and italic formatting and is long enough to test the wrapping behavior in such cases.\n- **Bold bullet point**\n- *Italic bullet point*", + "type": { + "$ref": "1" + }, + "optional": false, + "readOnly": false, + "discriminator": false, + "flatten": false, + "decorators": [], + "crossLanguageDefinitionId": "Documentation.Lists.BulletPointsModel.prop", + "serializationOptions": { + "json": { + "name": "prop" + } + }, + "isHttpMetadata": false + } + ] + }, + { + "$id": "10", + "kind": "model", + "name": "BulletPointsModelRequest", + "namespace": "Documentation.Lists", + "crossLanguageDefinitionId": "Documentation.Lists.bulletPointsModel.Request.anonymous", + "usage": "Spread,Json", + "decorators": [], + "properties": [ + { + "$id": "11", + "kind": "property", + "name": "input", + "serializedName": "input", + "type": { + "$ref": "8" + }, + "optional": false, + "readOnly": false, + "discriminator": false, + "flatten": false, + "decorators": [], + "crossLanguageDefinitionId": "Documentation.Lists.bulletPointsModel.input", + "serializationOptions": { + "json": { + "name": "input" + } + }, + "isHttpMetadata": false + } + ] + } + ], + "clients": [ + { + "$id": "12", + "kind": "client", + "name": "DocumentationClient", + "namespace": "Documentation", + "doc": "Illustrates documentation generation and formatting features", + "methods": [], + "parameters": [ + { + "$id": "13", + "kind": "endpoint", + "name": "endpoint", + "serializedName": "endpoint", + "doc": "Service host", + "type": { + "$id": "14", + "kind": "url", + "name": "endpoint", + "crossLanguageDefinitionId": "TypeSpec.url" + }, + "isApiVersion": false, + "optional": false, + "scope": "Client", + "isEndpoint": true, + "defaultValue": { + "type": { + "$id": "15", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string" + }, + "value": "http://localhost:3000" + }, + "serverUrlTemplate": "{endpoint}", + "skipUrlEncoding": false, + "readOnly": false, + "crossLanguageDefinitionId": "Documentation.endpoint" + } + ], + "initializedBy": 1, + "decorators": [], + "crossLanguageDefinitionId": "Documentation", + "apiVersions": [], + "children": [ + { + "$id": "16", + "kind": "client", + "name": "Lists", + "namespace": "Documentation.Lists", + "methods": [ + { + "$id": "17", + "kind": "basic", + "name": "bulletPointsOp", + "accessibility": "public", + "apiVersions": [], + "doc": "This tests:\n- Simple bullet point. This bullet point is going to be very long to test how text wrapping is handled in bullet points within documentation comments. It should properly indent the wrapped lines.\n- Another bullet point with **bold text**. This bullet point is also intentionally long to see how the formatting is preserved when the text wraps onto multiple lines in the generated documentation.\n- Third bullet point with *italic text*. Similar to the previous points, this one is extended to ensure that the wrapping and formatting are correctly applied in the output.\n- Complex bullet point with **bold** and *italic* combined. This bullet point combines both bold and italic formatting and is long enough to test the wrapping behavior in such cases.\n- **Bold bullet point**: A bullet point that is entirely bolded. This point is also made lengthy to observe how the bold formatting is maintained across wrapped lines.\n- *Italic bullet point*: A bullet point that is entirely italicized. This final point is extended to verify that italic formatting is correctly applied even when the text spans multiple lines.", + "operation": { + "$id": "18", + "name": "bulletPointsOp", + "resourceName": "Lists", + "doc": "This tests:\n- Simple bullet point. This bullet point is going to be very long to test how text wrapping is handled in bullet points within documentation comments. It should properly indent the wrapped lines.\n- Another bullet point with **bold text**. This bullet point is also intentionally long to see how the formatting is preserved when the text wraps onto multiple lines in the generated documentation.\n- Third bullet point with *italic text*. Similar to the previous points, this one is extended to ensure that the wrapping and formatting are correctly applied in the output.\n- Complex bullet point with **bold** and *italic* combined. This bullet point combines both bold and italic formatting and is long enough to test the wrapping behavior in such cases.\n- **Bold bullet point**: A bullet point that is entirely bolded. This point is also made lengthy to observe how the bold formatting is maintained across wrapped lines.\n- *Italic bullet point*: A bullet point that is entirely italicized. This final point is extended to verify that italic formatting is correctly applied even when the text spans multiple lines.", + "accessibility": "public", + "parameters": [], + "responses": [ + { + "statusCodes": [ + 204 + ], + "headers": [], + "isErrorResponse": false + } + ], + "httpMethod": "GET", + "uri": "{endpoint}", + "path": "/documentation/lists/bullet-points/op", + "bufferResponse": true, + "generateProtocolMethod": true, + "generateConvenienceMethod": true, + "crossLanguageDefinitionId": "Documentation.Lists.bulletPointsOp", + "decorators": [] + }, + "parameters": [], + "response": {}, + "isOverride": false, + "generateConvenient": true, + "generateProtocol": true, + "crossLanguageDefinitionId": "Documentation.Lists.bulletPointsOp" + }, + { + "$id": "19", + "kind": "basic", + "name": "bulletPointsModel", + "accessibility": "public", + "apiVersions": [], + "operation": { + "$id": "20", + "name": "bulletPointsModel", + "resourceName": "Lists", + "accessibility": "public", + "parameters": [ + { + "$id": "21", + "kind": "header", + "name": "contentType", + "serializedName": "Content-Type", + "doc": "Body parameter's content type. Known values are application/json", + "type": { + "$ref": "6" + }, + "isApiVersion": false, + "optional": false, + "isContentType": true, + "scope": "Constant", + "readOnly": false, + "decorators": [], + "crossLanguageDefinitionId": "Documentation.Lists.bulletPointsModel.contentType" + }, + { + "$id": "22", + "kind": "body", + "name": "bulletPointsModelRequest", + "serializedName": "bulletPointsModelRequest", + "type": { + "$ref": "10" + }, + "isApiVersion": false, + "contentTypes": [ + "application/json" + ], + "defaultContentType": "application/json", + "optional": false, + "scope": "Spread", + "decorators": [], + "readOnly": false, + "crossLanguageDefinitionId": "Documentation.Lists.bulletPointsModel.body" + } + ], + "responses": [ + { + "statusCodes": [ + 204 + ], + "headers": [], + "isErrorResponse": false + } + ], + "httpMethod": "POST", + "uri": "{endpoint}", + "path": "/documentation/lists/bullet-points/model", + "requestMediaTypes": [ + "application/json" + ], + "bufferResponse": true, + "generateProtocolMethod": true, + "generateConvenienceMethod": true, + "crossLanguageDefinitionId": "Documentation.Lists.bulletPointsModel", + "decorators": [] + }, + "parameters": [ + { + "$id": "23", + "kind": "method", + "name": "input", + "serializedName": "input", + "type": { + "$ref": "8" + }, + "location": "Body", + "isApiVersion": false, + "optional": false, + "scope": "Method", + "crossLanguageDefinitionId": "Documentation.Lists.bulletPointsModel.input", + "readOnly": false, + "access": "public", + "decorators": [] + }, + { + "$id": "24", + "kind": "method", + "name": "contentType", + "serializedName": "Content-Type", + "doc": "Body parameter's content type. Known values are application/json", + "type": { + "$ref": "6" + }, + "location": "Header", + "isApiVersion": false, + "optional": false, + "scope": "Constant", + "crossLanguageDefinitionId": "Documentation.Lists.bulletPointsModel.contentType", + "readOnly": false, + "access": "public", + "decorators": [] + } + ], + "response": {}, + "isOverride": false, + "generateConvenient": true, + "generateProtocol": true, + "crossLanguageDefinitionId": "Documentation.Lists.bulletPointsModel" + }, + { + "$id": "25", + "kind": "basic", + "name": "numbered", + "accessibility": "public", + "apiVersions": [], + "doc": "Steps to follow:\n1. First step with **important** note\n2. Second step with *emphasis*\n3. Third step combining **bold** and *italic*\n4. **Final step**: Review all steps for *accuracy*.", + "operation": { + "$id": "26", + "name": "numbered", + "resourceName": "Lists", + "doc": "Steps to follow:\n1. First step with **important** note\n2. Second step with *emphasis*\n3. Third step combining **bold** and *italic*\n4. **Final step**: Review all steps for *accuracy*.", + "accessibility": "public", + "parameters": [], + "responses": [ + { + "statusCodes": [ + 204 + ], + "headers": [], + "isErrorResponse": false + } + ], + "httpMethod": "GET", + "uri": "{endpoint}", + "path": "/documentation/lists/numbered", + "bufferResponse": true, + "generateProtocolMethod": true, + "generateConvenienceMethod": true, + "crossLanguageDefinitionId": "Documentation.Lists.numbered", + "decorators": [] + }, + "parameters": [], + "response": {}, + "isOverride": false, + "generateConvenient": true, + "generateProtocol": true, + "crossLanguageDefinitionId": "Documentation.Lists.numbered" + } + ], + "parameters": [ + { + "$id": "27", + "kind": "endpoint", + "name": "endpoint", + "serializedName": "endpoint", + "doc": "Service host", + "type": { + "$id": "28", + "kind": "url", + "name": "endpoint", + "crossLanguageDefinitionId": "TypeSpec.url" + }, + "isApiVersion": false, + "optional": false, + "scope": "Client", + "isEndpoint": true, + "defaultValue": { + "type": { + "$id": "29", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string" + }, + "value": "http://localhost:3000" + }, + "serverUrlTemplate": "{endpoint}", + "skipUrlEncoding": false, + "readOnly": false, + "crossLanguageDefinitionId": "Documentation.endpoint" + } + ], + "initializedBy": 0, + "decorators": [], + "crossLanguageDefinitionId": "Documentation.Lists", + "apiVersions": [], + "parent": { + "$ref": "12" + } + }, + { + "$id": "30", + "kind": "client", + "name": "TextFormatting", + "namespace": "Documentation.TextFormatting", + "methods": [ + { + "$id": "31", + "kind": "basic", + "name": "boldText", + "accessibility": "public", + "apiVersions": [], + "doc": "This is **bold text** in the middle of a sentence.\nThis is a sentence with **multiple bold** sections and **another bold** section.\n**This entire sentence is bold.**", + "operation": { + "$id": "32", + "name": "boldText", + "resourceName": "TextFormatting", + "doc": "This is **bold text** in the middle of a sentence.\nThis is a sentence with **multiple bold** sections and **another bold** section.\n**This entire sentence is bold.**", + "accessibility": "public", + "parameters": [], + "responses": [ + { + "statusCodes": [ + 204 + ], + "headers": [], + "isErrorResponse": false + } + ], + "httpMethod": "GET", + "uri": "{endpoint}", + "path": "/documentation/text-formatting/bold", + "bufferResponse": true, + "generateProtocolMethod": true, + "generateConvenienceMethod": true, + "crossLanguageDefinitionId": "Documentation.TextFormatting.boldText", + "decorators": [] + }, + "parameters": [], + "response": {}, + "isOverride": false, + "generateConvenient": true, + "generateProtocol": true, + "crossLanguageDefinitionId": "Documentation.TextFormatting.boldText" + }, + { + "$id": "33", + "kind": "basic", + "name": "italicText", + "accessibility": "public", + "apiVersions": [], + "doc": "This is *italic text* in the middle of a sentence.\nThis is a sentence with *multiple italic* sections and *another italic* section.\n*This entire sentence is italic.*", + "operation": { + "$id": "34", + "name": "italicText", + "resourceName": "TextFormatting", + "doc": "This is *italic text* in the middle of a sentence.\nThis is a sentence with *multiple italic* sections and *another italic* section.\n*This entire sentence is italic.*", + "accessibility": "public", + "parameters": [], + "responses": [ + { + "statusCodes": [ + 204 + ], + "headers": [], + "isErrorResponse": false + } + ], + "httpMethod": "GET", + "uri": "{endpoint}", + "path": "/documentation/text-formatting/italic", + "bufferResponse": true, + "generateProtocolMethod": true, + "generateConvenienceMethod": true, + "crossLanguageDefinitionId": "Documentation.TextFormatting.italicText", + "decorators": [] + }, + "parameters": [], + "response": {}, + "isOverride": false, + "generateConvenient": true, + "generateProtocol": true, + "crossLanguageDefinitionId": "Documentation.TextFormatting.italicText" + }, + { + "$id": "35", + "kind": "basic", + "name": "combinedFormatting", + "accessibility": "public", + "apiVersions": [], + "doc": "This sentence has **bold**, *italic*, and ***bold italic*** text.\nYou can also combine them like **bold with *italic inside* bold**.\nOr *italic with **bold inside** italic*.\nThis is a sentence with **bold**, *italic*, and ***bold italic*** text.", + "operation": { + "$id": "36", + "name": "combinedFormatting", + "resourceName": "TextFormatting", + "doc": "This sentence has **bold**, *italic*, and ***bold italic*** text.\nYou can also combine them like **bold with *italic inside* bold**.\nOr *italic with **bold inside** italic*.\nThis is a sentence with **bold**, *italic*, and ***bold italic*** text.", + "accessibility": "public", + "parameters": [], + "responses": [ + { + "statusCodes": [ + 204 + ], + "headers": [], + "isErrorResponse": false + } + ], + "httpMethod": "GET", + "uri": "{endpoint}", + "path": "/documentation/text-formatting/combined", + "bufferResponse": true, + "generateProtocolMethod": true, + "generateConvenienceMethod": true, + "crossLanguageDefinitionId": "Documentation.TextFormatting.combinedFormatting", + "decorators": [] + }, + "parameters": [], + "response": {}, + "isOverride": false, + "generateConvenient": true, + "generateProtocol": true, + "crossLanguageDefinitionId": "Documentation.TextFormatting.combinedFormatting" + } + ], + "parameters": [ + { + "$id": "37", + "kind": "endpoint", + "name": "endpoint", + "serializedName": "endpoint", + "doc": "Service host", + "type": { + "$id": "38", + "kind": "url", + "name": "endpoint", + "crossLanguageDefinitionId": "TypeSpec.url" + }, + "isApiVersion": false, + "optional": false, + "scope": "Client", + "isEndpoint": true, + "defaultValue": { + "type": { + "$id": "39", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string" + }, + "value": "http://localhost:3000" + }, + "serverUrlTemplate": "{endpoint}", + "skipUrlEncoding": false, + "readOnly": false, + "crossLanguageDefinitionId": "Documentation.endpoint" + } + ], + "initializedBy": 0, + "decorators": [], + "crossLanguageDefinitionId": "Documentation.TextFormatting", + "apiVersions": [], + "parent": { + "$ref": "12" + } + } + ] + } + ] +} diff --git a/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/Configuration.json b/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/Configuration.json new file mode 100644 index 00000000000..8bd0bb4f945 --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/Configuration.json @@ -0,0 +1,3 @@ +{ + "package-name": "Encode.Array" +} diff --git a/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/Encode.Array.sln b/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/Encode.Array.sln new file mode 100644 index 00000000000..112586204f8 --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/Encode.Array.sln @@ -0,0 +1,48 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Encode.Array", "src\Encode.Array.csproj", "{28FF4005-4467-4E36-92E7-DEA27DEB1519}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B0C276D1-2930-4887-B29A-D1A33E7009A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B0C276D1-2930-4887-B29A-D1A33E7009A2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B0C276D1-2930-4887-B29A-D1A33E7009A2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B0C276D1-2930-4887-B29A-D1A33E7009A2}.Release|Any CPU.Build.0 = Release|Any CPU + {8E9A77AC-792A-4432-8320-ACFD46730401}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8E9A77AC-792A-4432-8320-ACFD46730401}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8E9A77AC-792A-4432-8320-ACFD46730401}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8E9A77AC-792A-4432-8320-ACFD46730401}.Release|Any CPU.Build.0 = Release|Any CPU + {A4241C1F-A53D-474C-9E4E-075054407E74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A4241C1F-A53D-474C-9E4E-075054407E74}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A4241C1F-A53D-474C-9E4E-075054407E74}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A4241C1F-A53D-474C-9E4E-075054407E74}.Release|Any CPU.Build.0 = Release|Any CPU + {FA8BD3F1-8616-47B6-974C-7576CDF4717E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FA8BD3F1-8616-47B6-974C-7576CDF4717E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FA8BD3F1-8616-47B6-974C-7576CDF4717E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FA8BD3F1-8616-47B6-974C-7576CDF4717E}.Release|Any CPU.Build.0 = Release|Any CPU + {85677AD3-C214-42FA-AE6E-49B956CAC8DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {85677AD3-C214-42FA-AE6E-49B956CAC8DC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {85677AD3-C214-42FA-AE6E-49B956CAC8DC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {85677AD3-C214-42FA-AE6E-49B956CAC8DC}.Release|Any CPU.Build.0 = Release|Any CPU + {28FF4005-4467-4E36-92E7-DEA27DEB1519}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {28FF4005-4467-4E36-92E7-DEA27DEB1519}.Debug|Any CPU.Build.0 = Debug|Any CPU + {28FF4005-4467-4E36-92E7-DEA27DEB1519}.Release|Any CPU.ActiveCfg = Release|Any CPU + {28FF4005-4467-4E36-92E7-DEA27DEB1519}.Release|Any CPU.Build.0 = Release|Any CPU + {1F1CD1D4-9932-4B73-99D8-C252A67D4B46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1F1CD1D4-9932-4B73-99D8-C252A67D4B46}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1F1CD1D4-9932-4B73-99D8-C252A67D4B46}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1F1CD1D4-9932-4B73-99D8-C252A67D4B46}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {A97F4B90-2591-4689-B1F8-5F21FE6D6CAE} + EndGlobalSection +EndGlobal diff --git a/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Encode.Array.csproj b/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Encode.Array.csproj new file mode 100644 index 00000000000..36a5912701b --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Encode.Array.csproj @@ -0,0 +1,15 @@ + + + This is the Encode.Array client library for developing .NET applications with rich experience. + SDK Code Generation Encode.Array + 1.0.0-beta.1 + Encode.Array + netstandard2.0;net8.0 + latest + true + + + + + + diff --git a/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/ArrayClient.cs b/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/ArrayClient.cs new file mode 100644 index 00000000000..55ae5b366f0 --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/ArrayClient.cs @@ -0,0 +1,21 @@ +// + +#nullable disable + +using System; +using System.ClientModel.Primitives; +using Encode._Array._Property; + +namespace Encode._Array +{ + public partial class ArrayClient + { + public ArrayClient() : this(new Uri("http://localhost:3000"), new ArrayClientOptions()) => throw null; + + public ArrayClient(Uri endpoint, ArrayClientOptions options) => throw null; + + public ClientPipeline Pipeline => throw null; + + public virtual Property GetPropertyClient() => throw null; + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/ArrayClientOptions.cs b/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/ArrayClientOptions.cs new file mode 100644 index 00000000000..392d2e67a55 --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/ArrayClientOptions.cs @@ -0,0 +1,12 @@ +// + +#nullable disable + +using System.ClientModel.Primitives; + +namespace Encode._Array +{ + public partial class ArrayClientOptions : ClientPipelineOptions + { + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/EncodeArrayModelFactory.cs b/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/EncodeArrayModelFactory.cs new file mode 100644 index 00000000000..f1b065009ce --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/EncodeArrayModelFactory.cs @@ -0,0 +1,19 @@ +// + +#nullable disable + +using System.Collections.Generic; + +namespace Encode._Array +{ + public static partial class EncodeArrayModelFactory + { + public static CommaDelimitedArrayProperty CommaDelimitedArrayProperty(IEnumerable value = default) => throw null; + + public static SpaceDelimitedArrayProperty SpaceDelimitedArrayProperty(IEnumerable value = default) => throw null; + + public static PipeDelimitedArrayProperty PipeDelimitedArrayProperty(IEnumerable value = default) => throw null; + + public static NewlineDelimitedArrayProperty NewlineDelimitedArrayProperty(IEnumerable value = default) => throw null; + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Models/CommaDelimitedArrayProperty.Serialization.cs b/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Models/CommaDelimitedArrayProperty.Serialization.cs new file mode 100644 index 00000000000..c0c7fbd4732 --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Models/CommaDelimitedArrayProperty.Serialization.cs @@ -0,0 +1,38 @@ +// + +#nullable disable + +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Text.Json; + +namespace Encode._Array +{ + public partial class CommaDelimitedArrayProperty : IJsonModel + { + internal CommaDelimitedArrayProperty() => throw null; + + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) => throw null; + + protected virtual void JsonModelWriteCore(Utf8JsonWriter writer, ModelReaderWriterOptions options) => throw null; + + CommaDelimitedArrayProperty IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) => throw null; + + protected virtual CommaDelimitedArrayProperty JsonModelCreateCore(ref Utf8JsonReader reader, ModelReaderWriterOptions options) => throw null; + + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) => throw null; + + protected virtual BinaryData PersistableModelWriteCore(ModelReaderWriterOptions options) => throw null; + + CommaDelimitedArrayProperty IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) => throw null; + + protected virtual CommaDelimitedArrayProperty PersistableModelCreateCore(BinaryData data, ModelReaderWriterOptions options) => throw null; + + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => throw null; + + public static implicit operator BinaryContent(CommaDelimitedArrayProperty commaDelimitedArrayProperty) => throw null; + + public static explicit operator CommaDelimitedArrayProperty(ClientResult result) => throw null; + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Models/CommaDelimitedArrayProperty.cs b/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Models/CommaDelimitedArrayProperty.cs new file mode 100644 index 00000000000..9e62fadd600 --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Models/CommaDelimitedArrayProperty.cs @@ -0,0 +1,15 @@ +// + +#nullable disable + +using System.Collections.Generic; + +namespace Encode._Array +{ + public partial class CommaDelimitedArrayProperty + { + public CommaDelimitedArrayProperty(IEnumerable value) => throw null; + + public IList Value => throw null; + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Models/Encode_ArrayContext.cs b/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Models/Encode_ArrayContext.cs new file mode 100644 index 00000000000..f3ab669d97b --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Models/Encode_ArrayContext.cs @@ -0,0 +1,16 @@ +// + +#nullable disable + +using System.ClientModel.Primitives; + +namespace Encode._Array +{ + [ModelReaderWriterBuildable(typeof(CommaDelimitedArrayProperty))] + [ModelReaderWriterBuildable(typeof(NewlineDelimitedArrayProperty))] + [ModelReaderWriterBuildable(typeof(PipeDelimitedArrayProperty))] + [ModelReaderWriterBuildable(typeof(SpaceDelimitedArrayProperty))] + public partial class Encode_ArrayContext : ModelReaderWriterContext + { + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Models/NewlineDelimitedArrayProperty.Serialization.cs b/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Models/NewlineDelimitedArrayProperty.Serialization.cs new file mode 100644 index 00000000000..cd31ef81498 --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Models/NewlineDelimitedArrayProperty.Serialization.cs @@ -0,0 +1,38 @@ +// + +#nullable disable + +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Text.Json; + +namespace Encode._Array +{ + public partial class NewlineDelimitedArrayProperty : IJsonModel + { + internal NewlineDelimitedArrayProperty() => throw null; + + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) => throw null; + + protected virtual void JsonModelWriteCore(Utf8JsonWriter writer, ModelReaderWriterOptions options) => throw null; + + NewlineDelimitedArrayProperty IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) => throw null; + + protected virtual NewlineDelimitedArrayProperty JsonModelCreateCore(ref Utf8JsonReader reader, ModelReaderWriterOptions options) => throw null; + + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) => throw null; + + protected virtual BinaryData PersistableModelWriteCore(ModelReaderWriterOptions options) => throw null; + + NewlineDelimitedArrayProperty IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) => throw null; + + protected virtual NewlineDelimitedArrayProperty PersistableModelCreateCore(BinaryData data, ModelReaderWriterOptions options) => throw null; + + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => throw null; + + public static implicit operator BinaryContent(NewlineDelimitedArrayProperty newlineDelimitedArrayProperty) => throw null; + + public static explicit operator NewlineDelimitedArrayProperty(ClientResult result) => throw null; + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Models/NewlineDelimitedArrayProperty.cs b/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Models/NewlineDelimitedArrayProperty.cs new file mode 100644 index 00000000000..1680d3dcc06 --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Models/NewlineDelimitedArrayProperty.cs @@ -0,0 +1,15 @@ +// + +#nullable disable + +using System.Collections.Generic; + +namespace Encode._Array +{ + public partial class NewlineDelimitedArrayProperty + { + public NewlineDelimitedArrayProperty(IEnumerable value) => throw null; + + public IList Value => throw null; + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Models/PipeDelimitedArrayProperty.Serialization.cs b/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Models/PipeDelimitedArrayProperty.Serialization.cs new file mode 100644 index 00000000000..77fb59cc6da --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Models/PipeDelimitedArrayProperty.Serialization.cs @@ -0,0 +1,38 @@ +// + +#nullable disable + +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Text.Json; + +namespace Encode._Array +{ + public partial class PipeDelimitedArrayProperty : IJsonModel + { + internal PipeDelimitedArrayProperty() => throw null; + + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) => throw null; + + protected virtual void JsonModelWriteCore(Utf8JsonWriter writer, ModelReaderWriterOptions options) => throw null; + + PipeDelimitedArrayProperty IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) => throw null; + + protected virtual PipeDelimitedArrayProperty JsonModelCreateCore(ref Utf8JsonReader reader, ModelReaderWriterOptions options) => throw null; + + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) => throw null; + + protected virtual BinaryData PersistableModelWriteCore(ModelReaderWriterOptions options) => throw null; + + PipeDelimitedArrayProperty IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) => throw null; + + protected virtual PipeDelimitedArrayProperty PersistableModelCreateCore(BinaryData data, ModelReaderWriterOptions options) => throw null; + + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => throw null; + + public static implicit operator BinaryContent(PipeDelimitedArrayProperty pipeDelimitedArrayProperty) => throw null; + + public static explicit operator PipeDelimitedArrayProperty(ClientResult result) => throw null; + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Models/PipeDelimitedArrayProperty.cs b/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Models/PipeDelimitedArrayProperty.cs new file mode 100644 index 00000000000..a8267bbaf53 --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Models/PipeDelimitedArrayProperty.cs @@ -0,0 +1,15 @@ +// + +#nullable disable + +using System.Collections.Generic; + +namespace Encode._Array +{ + public partial class PipeDelimitedArrayProperty + { + public PipeDelimitedArrayProperty(IEnumerable value) => throw null; + + public IList Value => throw null; + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Models/SpaceDelimitedArrayProperty.Serialization.cs b/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Models/SpaceDelimitedArrayProperty.Serialization.cs new file mode 100644 index 00000000000..d37d4f47a96 --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Models/SpaceDelimitedArrayProperty.Serialization.cs @@ -0,0 +1,38 @@ +// + +#nullable disable + +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Text.Json; + +namespace Encode._Array +{ + public partial class SpaceDelimitedArrayProperty : IJsonModel + { + internal SpaceDelimitedArrayProperty() => throw null; + + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) => throw null; + + protected virtual void JsonModelWriteCore(Utf8JsonWriter writer, ModelReaderWriterOptions options) => throw null; + + SpaceDelimitedArrayProperty IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) => throw null; + + protected virtual SpaceDelimitedArrayProperty JsonModelCreateCore(ref Utf8JsonReader reader, ModelReaderWriterOptions options) => throw null; + + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) => throw null; + + protected virtual BinaryData PersistableModelWriteCore(ModelReaderWriterOptions options) => throw null; + + SpaceDelimitedArrayProperty IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) => throw null; + + protected virtual SpaceDelimitedArrayProperty PersistableModelCreateCore(BinaryData data, ModelReaderWriterOptions options) => throw null; + + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => throw null; + + public static implicit operator BinaryContent(SpaceDelimitedArrayProperty spaceDelimitedArrayProperty) => throw null; + + public static explicit operator SpaceDelimitedArrayProperty(ClientResult result) => throw null; + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Models/SpaceDelimitedArrayProperty.cs b/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Models/SpaceDelimitedArrayProperty.cs new file mode 100644 index 00000000000..e93bddfb965 --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Models/SpaceDelimitedArrayProperty.cs @@ -0,0 +1,15 @@ +// + +#nullable disable + +using System.Collections.Generic; + +namespace Encode._Array +{ + public partial class SpaceDelimitedArrayProperty + { + public SpaceDelimitedArrayProperty(IEnumerable value) => throw null; + + public IList Value => throw null; + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Property.cs b/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Property.cs new file mode 100644 index 00000000000..e50400b6ee6 --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/src/Generated/Property.cs @@ -0,0 +1,51 @@ +// + +#nullable disable + +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Threading; +using System.Threading.Tasks; +using Encode._Array; + +namespace Encode._Array._Property +{ + public partial class Property + { + protected Property() => throw null; + + public ClientPipeline Pipeline => throw null; + + public virtual ClientResult CommaDelimited(BinaryContent content, RequestOptions options = null) => throw null; + + public virtual Task CommaDelimitedAsync(BinaryContent content, RequestOptions options = null) => throw null; + + public virtual ClientResult CommaDelimited(CommaDelimitedArrayProperty body, CancellationToken cancellationToken = default) => throw null; + + public virtual Task> CommaDelimitedAsync(CommaDelimitedArrayProperty body, CancellationToken cancellationToken = default) => throw null; + + public virtual ClientResult SpaceDelimited(BinaryContent content, RequestOptions options = null) => throw null; + + public virtual Task SpaceDelimitedAsync(BinaryContent content, RequestOptions options = null) => throw null; + + public virtual ClientResult SpaceDelimited(SpaceDelimitedArrayProperty body, CancellationToken cancellationToken = default) => throw null; + + public virtual Task> SpaceDelimitedAsync(SpaceDelimitedArrayProperty body, CancellationToken cancellationToken = default) => throw null; + + public virtual ClientResult PipeDelimited(BinaryContent content, RequestOptions options = null) => throw null; + + public virtual Task PipeDelimitedAsync(BinaryContent content, RequestOptions options = null) => throw null; + + public virtual ClientResult PipeDelimited(PipeDelimitedArrayProperty body, CancellationToken cancellationToken = default) => throw null; + + public virtual Task> PipeDelimitedAsync(PipeDelimitedArrayProperty body, CancellationToken cancellationToken = default) => throw null; + + public virtual ClientResult NewlineDelimited(BinaryContent content, RequestOptions options = null) => throw null; + + public virtual Task NewlineDelimitedAsync(BinaryContent content, RequestOptions options = null) => throw null; + + public virtual ClientResult NewlineDelimited(NewlineDelimitedArrayProperty body, CancellationToken cancellationToken = default) => throw null; + + public virtual Task> NewlineDelimitedAsync(NewlineDelimitedArrayProperty body, CancellationToken cancellationToken = default) => throw null; + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/tspCodeModel.json b/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/tspCodeModel.json new file mode 100644 index 00000000000..61e145502cc --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Spector/http/encode/array/tspCodeModel.json @@ -0,0 +1,995 @@ +{ + "name": "Encode.Array", + "apiVersions": [], + "enums": [], + "constants": [ + { + "$id": "1", + "kind": "constant", + "name": "commaDelimitedContentType", + "namespace": "", + "usage": "None", + "valueType": { + "$id": "2", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "value": "application/json", + "decorators": [] + }, + { + "$id": "3", + "kind": "constant", + "name": "commaDelimitedContentType1", + "namespace": "", + "usage": "None", + "valueType": { + "$id": "4", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "value": "application/json", + "decorators": [] + }, + { + "$id": "5", + "kind": "constant", + "name": "spaceDelimitedContentType", + "namespace": "", + "usage": "None", + "valueType": { + "$id": "6", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "value": "application/json", + "decorators": [] + }, + { + "$id": "7", + "kind": "constant", + "name": "spaceDelimitedContentType1", + "namespace": "", + "usage": "None", + "valueType": { + "$id": "8", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "value": "application/json", + "decorators": [] + }, + { + "$id": "9", + "kind": "constant", + "name": "pipeDelimitedContentType", + "namespace": "", + "usage": "None", + "valueType": { + "$id": "10", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "value": "application/json", + "decorators": [] + }, + { + "$id": "11", + "kind": "constant", + "name": "pipeDelimitedContentType1", + "namespace": "", + "usage": "None", + "valueType": { + "$id": "12", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "value": "application/json", + "decorators": [] + }, + { + "$id": "13", + "kind": "constant", + "name": "newlineDelimitedContentType", + "namespace": "", + "usage": "None", + "valueType": { + "$id": "14", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "value": "application/json", + "decorators": [] + }, + { + "$id": "15", + "kind": "constant", + "name": "newlineDelimitedContentType1", + "namespace": "", + "usage": "None", + "valueType": { + "$id": "16", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "value": "application/json", + "decorators": [] + } + ], + "models": [ + { + "$id": "17", + "kind": "model", + "name": "CommaDelimitedArrayProperty", + "namespace": "Encode.Array", + "crossLanguageDefinitionId": "Encode.Array.CommaDelimitedArrayProperty", + "usage": "Input,Output,Json", + "decorators": [], + "properties": [ + { + "$id": "18", + "kind": "property", + "name": "value", + "serializedName": "value", + "type": { + "$id": "19", + "kind": "array", + "name": "Array", + "valueType": { + "$id": "20", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "crossLanguageDefinitionId": "TypeSpec.Array", + "decorators": [] + }, + "optional": false, + "readOnly": false, + "discriminator": false, + "flatten": false, + "decorators": [], + "crossLanguageDefinitionId": "Encode.Array.CommaDelimitedArrayProperty.value", + "serializationOptions": { + "json": { + "name": "value" + } + }, + "isHttpMetadata": false + } + ] + }, + { + "$id": "21", + "kind": "model", + "name": "SpaceDelimitedArrayProperty", + "namespace": "Encode.Array", + "crossLanguageDefinitionId": "Encode.Array.SpaceDelimitedArrayProperty", + "usage": "Input,Output,Json", + "decorators": [], + "properties": [ + { + "$id": "22", + "kind": "property", + "name": "value", + "serializedName": "value", + "type": { + "$ref": "19" + }, + "optional": false, + "readOnly": false, + "discriminator": false, + "flatten": false, + "decorators": [], + "crossLanguageDefinitionId": "Encode.Array.SpaceDelimitedArrayProperty.value", + "serializationOptions": { + "json": { + "name": "value" + } + }, + "isHttpMetadata": false + } + ] + }, + { + "$id": "23", + "kind": "model", + "name": "PipeDelimitedArrayProperty", + "namespace": "Encode.Array", + "crossLanguageDefinitionId": "Encode.Array.PipeDelimitedArrayProperty", + "usage": "Input,Output,Json", + "decorators": [], + "properties": [ + { + "$id": "24", + "kind": "property", + "name": "value", + "serializedName": "value", + "type": { + "$ref": "19" + }, + "optional": false, + "readOnly": false, + "discriminator": false, + "flatten": false, + "decorators": [], + "crossLanguageDefinitionId": "Encode.Array.PipeDelimitedArrayProperty.value", + "serializationOptions": { + "json": { + "name": "value" + } + }, + "isHttpMetadata": false + } + ] + }, + { + "$id": "25", + "kind": "model", + "name": "NewlineDelimitedArrayProperty", + "namespace": "Encode.Array", + "crossLanguageDefinitionId": "Encode.Array.NewlineDelimitedArrayProperty", + "usage": "Input,Output,Json", + "decorators": [], + "properties": [ + { + "$id": "26", + "kind": "property", + "name": "value", + "serializedName": "value", + "type": { + "$ref": "19" + }, + "optional": false, + "readOnly": false, + "discriminator": false, + "flatten": false, + "decorators": [], + "crossLanguageDefinitionId": "Encode.Array.NewlineDelimitedArrayProperty.value", + "serializationOptions": { + "json": { + "name": "value" + } + }, + "isHttpMetadata": false + } + ] + } + ], + "clients": [ + { + "$id": "27", + "kind": "client", + "name": "ArrayClient", + "namespace": "Encode.Array", + "doc": "Test for encode decorator on array.", + "methods": [], + "parameters": [ + { + "$id": "28", + "kind": "endpoint", + "name": "endpoint", + "serializedName": "endpoint", + "doc": "Service host", + "type": { + "$id": "29", + "kind": "url", + "name": "endpoint", + "crossLanguageDefinitionId": "TypeSpec.url" + }, + "isApiVersion": false, + "optional": false, + "scope": "Client", + "isEndpoint": true, + "defaultValue": { + "type": { + "$id": "30", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string" + }, + "value": "http://localhost:3000" + }, + "serverUrlTemplate": "{endpoint}", + "skipUrlEncoding": false, + "readOnly": false, + "crossLanguageDefinitionId": "Encode.Array.endpoint" + } + ], + "initializedBy": 1, + "decorators": [], + "crossLanguageDefinitionId": "Encode.Array", + "apiVersions": [], + "children": [ + { + "$id": "31", + "kind": "client", + "name": "Property", + "namespace": "Encode.Array.Property", + "methods": [ + { + "$id": "32", + "kind": "basic", + "name": "commaDelimited", + "accessibility": "public", + "apiVersions": [], + "operation": { + "$id": "33", + "name": "commaDelimited", + "resourceName": "Property", + "accessibility": "public", + "parameters": [ + { + "$id": "34", + "kind": "header", + "name": "contentType", + "serializedName": "Content-Type", + "doc": "Body parameter's content type. Known values are application/json", + "type": { + "$ref": "1" + }, + "isApiVersion": false, + "optional": false, + "isContentType": true, + "scope": "Constant", + "readOnly": false, + "decorators": [], + "crossLanguageDefinitionId": "Encode.Array.Property.commaDelimited.contentType" + }, + { + "$id": "35", + "kind": "header", + "name": "accept", + "serializedName": "Accept", + "type": { + "$ref": "3" + }, + "isApiVersion": false, + "optional": false, + "isContentType": false, + "scope": "Constant", + "readOnly": false, + "decorators": [], + "crossLanguageDefinitionId": "Encode.Array.Property.commaDelimited.accept" + }, + { + "$id": "36", + "kind": "body", + "name": "body", + "serializedName": "body", + "type": { + "$ref": "17" + }, + "isApiVersion": false, + "contentTypes": [ + "application/json" + ], + "defaultContentType": "application/json", + "optional": false, + "scope": "Method", + "decorators": [], + "readOnly": false, + "crossLanguageDefinitionId": "Encode.Array.Property.commaDelimited.body" + } + ], + "responses": [ + { + "statusCodes": [ + 200 + ], + "bodyType": { + "$ref": "17" + }, + "headers": [], + "isErrorResponse": false, + "contentTypes": [ + "application/json" + ] + } + ], + "httpMethod": "POST", + "uri": "{endpoint}", + "path": "/encode/array/property/comma-delimited", + "requestMediaTypes": [ + "application/json" + ], + "bufferResponse": true, + "generateProtocolMethod": true, + "generateConvenienceMethod": true, + "crossLanguageDefinitionId": "Encode.Array.Property.commaDelimited", + "decorators": [] + }, + "parameters": [ + { + "$id": "37", + "kind": "method", + "name": "body", + "serializedName": "body", + "type": { + "$ref": "17" + }, + "location": "Body", + "isApiVersion": false, + "optional": false, + "scope": "Method", + "crossLanguageDefinitionId": "Encode.Array.Property.commaDelimited.body", + "readOnly": false, + "access": "public", + "decorators": [] + }, + { + "$id": "38", + "kind": "method", + "name": "contentType", + "serializedName": "Content-Type", + "doc": "Body parameter's content type. Known values are application/json", + "type": { + "$ref": "1" + }, + "location": "Header", + "isApiVersion": false, + "optional": false, + "scope": "Constant", + "crossLanguageDefinitionId": "Encode.Array.Property.commaDelimited.contentType", + "readOnly": false, + "access": "public", + "decorators": [] + }, + { + "$id": "39", + "kind": "method", + "name": "accept", + "serializedName": "Accept", + "type": { + "$ref": "3" + }, + "location": "Header", + "isApiVersion": false, + "optional": false, + "scope": "Constant", + "crossLanguageDefinitionId": "Encode.Array.Property.commaDelimited.accept", + "readOnly": false, + "access": "public", + "decorators": [] + } + ], + "response": { + "type": { + "$ref": "17" + } + }, + "isOverride": false, + "generateConvenient": true, + "generateProtocol": true, + "crossLanguageDefinitionId": "Encode.Array.Property.commaDelimited" + }, + { + "$id": "40", + "kind": "basic", + "name": "spaceDelimited", + "accessibility": "public", + "apiVersions": [], + "operation": { + "$id": "41", + "name": "spaceDelimited", + "resourceName": "Property", + "accessibility": "public", + "parameters": [ + { + "$id": "42", + "kind": "header", + "name": "contentType", + "serializedName": "Content-Type", + "doc": "Body parameter's content type. Known values are application/json", + "type": { + "$ref": "5" + }, + "isApiVersion": false, + "optional": false, + "isContentType": true, + "scope": "Constant", + "readOnly": false, + "decorators": [], + "crossLanguageDefinitionId": "Encode.Array.Property.spaceDelimited.contentType" + }, + { + "$id": "43", + "kind": "header", + "name": "accept", + "serializedName": "Accept", + "type": { + "$ref": "7" + }, + "isApiVersion": false, + "optional": false, + "isContentType": false, + "scope": "Constant", + "readOnly": false, + "decorators": [], + "crossLanguageDefinitionId": "Encode.Array.Property.spaceDelimited.accept" + }, + { + "$id": "44", + "kind": "body", + "name": "body", + "serializedName": "body", + "type": { + "$ref": "21" + }, + "isApiVersion": false, + "contentTypes": [ + "application/json" + ], + "defaultContentType": "application/json", + "optional": false, + "scope": "Method", + "decorators": [], + "readOnly": false, + "crossLanguageDefinitionId": "Encode.Array.Property.spaceDelimited.body" + } + ], + "responses": [ + { + "statusCodes": [ + 200 + ], + "bodyType": { + "$ref": "21" + }, + "headers": [], + "isErrorResponse": false, + "contentTypes": [ + "application/json" + ] + } + ], + "httpMethod": "POST", + "uri": "{endpoint}", + "path": "/encode/array/property/space-delimited", + "requestMediaTypes": [ + "application/json" + ], + "bufferResponse": true, + "generateProtocolMethod": true, + "generateConvenienceMethod": true, + "crossLanguageDefinitionId": "Encode.Array.Property.spaceDelimited", + "decorators": [] + }, + "parameters": [ + { + "$id": "45", + "kind": "method", + "name": "body", + "serializedName": "body", + "type": { + "$ref": "21" + }, + "location": "Body", + "isApiVersion": false, + "optional": false, + "scope": "Method", + "crossLanguageDefinitionId": "Encode.Array.Property.spaceDelimited.body", + "readOnly": false, + "access": "public", + "decorators": [] + }, + { + "$id": "46", + "kind": "method", + "name": "contentType", + "serializedName": "Content-Type", + "doc": "Body parameter's content type. Known values are application/json", + "type": { + "$ref": "5" + }, + "location": "Header", + "isApiVersion": false, + "optional": false, + "scope": "Constant", + "crossLanguageDefinitionId": "Encode.Array.Property.spaceDelimited.contentType", + "readOnly": false, + "access": "public", + "decorators": [] + }, + { + "$id": "47", + "kind": "method", + "name": "accept", + "serializedName": "Accept", + "type": { + "$ref": "7" + }, + "location": "Header", + "isApiVersion": false, + "optional": false, + "scope": "Constant", + "crossLanguageDefinitionId": "Encode.Array.Property.spaceDelimited.accept", + "readOnly": false, + "access": "public", + "decorators": [] + } + ], + "response": { + "type": { + "$ref": "21" + } + }, + "isOverride": false, + "generateConvenient": true, + "generateProtocol": true, + "crossLanguageDefinitionId": "Encode.Array.Property.spaceDelimited" + }, + { + "$id": "48", + "kind": "basic", + "name": "pipeDelimited", + "accessibility": "public", + "apiVersions": [], + "operation": { + "$id": "49", + "name": "pipeDelimited", + "resourceName": "Property", + "accessibility": "public", + "parameters": [ + { + "$id": "50", + "kind": "header", + "name": "contentType", + "serializedName": "Content-Type", + "doc": "Body parameter's content type. Known values are application/json", + "type": { + "$ref": "9" + }, + "isApiVersion": false, + "optional": false, + "isContentType": true, + "scope": "Constant", + "readOnly": false, + "decorators": [], + "crossLanguageDefinitionId": "Encode.Array.Property.pipeDelimited.contentType" + }, + { + "$id": "51", + "kind": "header", + "name": "accept", + "serializedName": "Accept", + "type": { + "$ref": "11" + }, + "isApiVersion": false, + "optional": false, + "isContentType": false, + "scope": "Constant", + "readOnly": false, + "decorators": [], + "crossLanguageDefinitionId": "Encode.Array.Property.pipeDelimited.accept" + }, + { + "$id": "52", + "kind": "body", + "name": "body", + "serializedName": "body", + "type": { + "$ref": "23" + }, + "isApiVersion": false, + "contentTypes": [ + "application/json" + ], + "defaultContentType": "application/json", + "optional": false, + "scope": "Method", + "decorators": [], + "readOnly": false, + "crossLanguageDefinitionId": "Encode.Array.Property.pipeDelimited.body" + } + ], + "responses": [ + { + "statusCodes": [ + 200 + ], + "bodyType": { + "$ref": "23" + }, + "headers": [], + "isErrorResponse": false, + "contentTypes": [ + "application/json" + ] + } + ], + "httpMethod": "POST", + "uri": "{endpoint}", + "path": "/encode/array/property/pipe-delimited", + "requestMediaTypes": [ + "application/json" + ], + "bufferResponse": true, + "generateProtocolMethod": true, + "generateConvenienceMethod": true, + "crossLanguageDefinitionId": "Encode.Array.Property.pipeDelimited", + "decorators": [] + }, + "parameters": [ + { + "$id": "53", + "kind": "method", + "name": "body", + "serializedName": "body", + "type": { + "$ref": "23" + }, + "location": "Body", + "isApiVersion": false, + "optional": false, + "scope": "Method", + "crossLanguageDefinitionId": "Encode.Array.Property.pipeDelimited.body", + "readOnly": false, + "access": "public", + "decorators": [] + }, + { + "$id": "54", + "kind": "method", + "name": "contentType", + "serializedName": "Content-Type", + "doc": "Body parameter's content type. Known values are application/json", + "type": { + "$ref": "9" + }, + "location": "Header", + "isApiVersion": false, + "optional": false, + "scope": "Constant", + "crossLanguageDefinitionId": "Encode.Array.Property.pipeDelimited.contentType", + "readOnly": false, + "access": "public", + "decorators": [] + }, + { + "$id": "55", + "kind": "method", + "name": "accept", + "serializedName": "Accept", + "type": { + "$ref": "11" + }, + "location": "Header", + "isApiVersion": false, + "optional": false, + "scope": "Constant", + "crossLanguageDefinitionId": "Encode.Array.Property.pipeDelimited.accept", + "readOnly": false, + "access": "public", + "decorators": [] + } + ], + "response": { + "type": { + "$ref": "23" + } + }, + "isOverride": false, + "generateConvenient": true, + "generateProtocol": true, + "crossLanguageDefinitionId": "Encode.Array.Property.pipeDelimited" + }, + { + "$id": "56", + "kind": "basic", + "name": "newlineDelimited", + "accessibility": "public", + "apiVersions": [], + "operation": { + "$id": "57", + "name": "newlineDelimited", + "resourceName": "Property", + "accessibility": "public", + "parameters": [ + { + "$id": "58", + "kind": "header", + "name": "contentType", + "serializedName": "Content-Type", + "doc": "Body parameter's content type. Known values are application/json", + "type": { + "$ref": "13" + }, + "isApiVersion": false, + "optional": false, + "isContentType": true, + "scope": "Constant", + "readOnly": false, + "decorators": [], + "crossLanguageDefinitionId": "Encode.Array.Property.newlineDelimited.contentType" + }, + { + "$id": "59", + "kind": "header", + "name": "accept", + "serializedName": "Accept", + "type": { + "$ref": "15" + }, + "isApiVersion": false, + "optional": false, + "isContentType": false, + "scope": "Constant", + "readOnly": false, + "decorators": [], + "crossLanguageDefinitionId": "Encode.Array.Property.newlineDelimited.accept" + }, + { + "$id": "60", + "kind": "body", + "name": "body", + "serializedName": "body", + "type": { + "$ref": "25" + }, + "isApiVersion": false, + "contentTypes": [ + "application/json" + ], + "defaultContentType": "application/json", + "optional": false, + "scope": "Method", + "decorators": [], + "readOnly": false, + "crossLanguageDefinitionId": "Encode.Array.Property.newlineDelimited.body" + } + ], + "responses": [ + { + "statusCodes": [ + 200 + ], + "bodyType": { + "$ref": "25" + }, + "headers": [], + "isErrorResponse": false, + "contentTypes": [ + "application/json" + ] + } + ], + "httpMethod": "POST", + "uri": "{endpoint}", + "path": "/encode/array/property/newline-delimited", + "requestMediaTypes": [ + "application/json" + ], + "bufferResponse": true, + "generateProtocolMethod": true, + "generateConvenienceMethod": true, + "crossLanguageDefinitionId": "Encode.Array.Property.newlineDelimited", + "decorators": [] + }, + "parameters": [ + { + "$id": "61", + "kind": "method", + "name": "body", + "serializedName": "body", + "type": { + "$ref": "25" + }, + "location": "Body", + "isApiVersion": false, + "optional": false, + "scope": "Method", + "crossLanguageDefinitionId": "Encode.Array.Property.newlineDelimited.body", + "readOnly": false, + "access": "public", + "decorators": [] + }, + { + "$id": "62", + "kind": "method", + "name": "contentType", + "serializedName": "Content-Type", + "doc": "Body parameter's content type. Known values are application/json", + "type": { + "$ref": "13" + }, + "location": "Header", + "isApiVersion": false, + "optional": false, + "scope": "Constant", + "crossLanguageDefinitionId": "Encode.Array.Property.newlineDelimited.contentType", + "readOnly": false, + "access": "public", + "decorators": [] + }, + { + "$id": "63", + "kind": "method", + "name": "accept", + "serializedName": "Accept", + "type": { + "$ref": "15" + }, + "location": "Header", + "isApiVersion": false, + "optional": false, + "scope": "Constant", + "crossLanguageDefinitionId": "Encode.Array.Property.newlineDelimited.accept", + "readOnly": false, + "access": "public", + "decorators": [] + } + ], + "response": { + "type": { + "$ref": "25" + } + }, + "isOverride": false, + "generateConvenient": true, + "generateProtocol": true, + "crossLanguageDefinitionId": "Encode.Array.Property.newlineDelimited" + } + ], + "parameters": [ + { + "$id": "64", + "kind": "endpoint", + "name": "endpoint", + "serializedName": "endpoint", + "doc": "Service host", + "type": { + "$id": "65", + "kind": "url", + "name": "endpoint", + "crossLanguageDefinitionId": "TypeSpec.url" + }, + "isApiVersion": false, + "optional": false, + "scope": "Client", + "isEndpoint": true, + "defaultValue": { + "type": { + "$id": "66", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string" + }, + "value": "http://localhost:3000" + }, + "serverUrlTemplate": "{endpoint}", + "skipUrlEncoding": false, + "readOnly": false, + "crossLanguageDefinitionId": "Encode.Array.endpoint" + } + ], + "initializedBy": 0, + "decorators": [], + "crossLanguageDefinitionId": "Encode.Array.Property", + "apiVersions": [], + "parent": { + "$ref": "27" + } + } + ] + } + ] +} diff --git a/packages/http-client-csharp/generator/TestProjects/Spector/http/special-words/src/Generated/ModelProperties.cs b/packages/http-client-csharp/generator/TestProjects/Spector/http/special-words/src/Generated/ModelProperties.cs index 00c4b992da7..0fed89ca4f3 100644 --- a/packages/http-client-csharp/generator/TestProjects/Spector/http/special-words/src/Generated/ModelProperties.cs +++ b/packages/http-client-csharp/generator/TestProjects/Spector/http/special-words/src/Generated/ModelProperties.cs @@ -22,5 +22,13 @@ public partial class ModelProperties public virtual ClientResult SameAsModel(SameAsModel body, CancellationToken cancellationToken = default) => throw null; public virtual Task SameAsModelAsync(SameAsModel body, CancellationToken cancellationToken = default) => throw null; + + public virtual ClientResult DictMethods(BinaryContent content, RequestOptions options = null) => throw null; + + public virtual Task DictMethodsAsync(BinaryContent content, RequestOptions options = null) => throw null; + + public virtual ClientResult DictMethods(DictMethods body, CancellationToken cancellationToken = default) => throw null; + + public virtual Task DictMethodsAsync(DictMethods body, CancellationToken cancellationToken = default) => throw null; } } diff --git a/packages/http-client-csharp/generator/TestProjects/Spector/http/special-words/src/Generated/Models/DictMethods.Serialization.cs b/packages/http-client-csharp/generator/TestProjects/Spector/http/special-words/src/Generated/Models/DictMethods.Serialization.cs new file mode 100644 index 00000000000..f445a94dfb9 --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Spector/http/special-words/src/Generated/Models/DictMethods.Serialization.cs @@ -0,0 +1,36 @@ +// + +#nullable disable + +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Text.Json; + +namespace SpecialWords._ModelProperties +{ + public partial class DictMethods : IJsonModel + { + internal DictMethods() => throw null; + + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) => throw null; + + protected virtual void JsonModelWriteCore(Utf8JsonWriter writer, ModelReaderWriterOptions options) => throw null; + + DictMethods IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) => throw null; + + protected virtual DictMethods JsonModelCreateCore(ref Utf8JsonReader reader, ModelReaderWriterOptions options) => throw null; + + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) => throw null; + + protected virtual BinaryData PersistableModelWriteCore(ModelReaderWriterOptions options) => throw null; + + DictMethods IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) => throw null; + + protected virtual DictMethods PersistableModelCreateCore(BinaryData data, ModelReaderWriterOptions options) => throw null; + + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => throw null; + + public static implicit operator BinaryContent(DictMethods dictMethods) => throw null; + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Spector/http/special-words/src/Generated/Models/DictMethods.cs b/packages/http-client-csharp/generator/TestProjects/Spector/http/special-words/src/Generated/Models/DictMethods.cs new file mode 100644 index 00000000000..c1ae5820b24 --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Spector/http/special-words/src/Generated/Models/DictMethods.cs @@ -0,0 +1,31 @@ +// + +#nullable disable + +namespace SpecialWords._ModelProperties +{ + public partial class DictMethods + { + public DictMethods(string keys, string items, string values, string popitem, string clear, string update, string setdefault, string pop, string @get, string copy) => throw null; + + public string Keys => throw null; + + public string Items => throw null; + + public string Values => throw null; + + public string Popitem => throw null; + + public string Clear => throw null; + + public string Update => throw null; + + public string Setdefault => throw null; + + public string Pop => throw null; + + public string Get => throw null; + + public string Copy => throw null; + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Spector/http/special-words/src/Generated/Models/SpecialWordsContext.cs b/packages/http-client-csharp/generator/TestProjects/Spector/http/special-words/src/Generated/Models/SpecialWordsContext.cs index b09496e73b6..d04f06a1fa5 100644 --- a/packages/http-client-csharp/generator/TestProjects/Spector/http/special-words/src/Generated/Models/SpecialWordsContext.cs +++ b/packages/http-client-csharp/generator/TestProjects/Spector/http/special-words/src/Generated/Models/SpecialWordsContext.cs @@ -19,6 +19,7 @@ namespace SpecialWords [ModelReaderWriterBuildable(typeof(Continue))] [ModelReaderWriterBuildable(typeof(Def))] [ModelReaderWriterBuildable(typeof(Del))] + [ModelReaderWriterBuildable(typeof(DictMethods))] [ModelReaderWriterBuildable(typeof(Elif))] [ModelReaderWriterBuildable(typeof(Else))] [ModelReaderWriterBuildable(typeof(Except))] diff --git a/packages/http-client-csharp/generator/TestProjects/Spector/http/special-words/src/Generated/SpecialWordsModelFactory.cs b/packages/http-client-csharp/generator/TestProjects/Spector/http/special-words/src/Generated/SpecialWordsModelFactory.cs index 8e69221e0b4..9b130273a61 100644 --- a/packages/http-client-csharp/generator/TestProjects/Spector/http/special-words/src/Generated/SpecialWordsModelFactory.cs +++ b/packages/http-client-csharp/generator/TestProjects/Spector/http/special-words/src/Generated/SpecialWordsModelFactory.cs @@ -76,5 +76,7 @@ public static partial class SpecialWordsModelFactory public static Yield Yield(string name = default) => throw null; public static SameAsModel SameAsModel(string sameAsModelProperty = default) => throw null; + + public static DictMethods DictMethods(string keys = default, string items = default, string values = default, string popitem = default, string clear = default, string update = default, string setdefault = default, string pop = default, string @get = default, string copy = default) => throw null; } } diff --git a/packages/http-client-csharp/generator/TestProjects/Spector/http/special-words/tspCodeModel.json b/packages/http-client-csharp/generator/TestProjects/Spector/http/special-words/tspCodeModel.json index 3e16e55a89e..3d955baea83 100644 --- a/packages/http-client-csharp/generator/TestProjects/Spector/http/special-words/tspCodeModel.json +++ b/packages/http-client-csharp/generator/TestProjects/Spector/http/special-words/tspCodeModel.json @@ -546,11 +546,27 @@ }, "value": "application/json", "decorators": [] + }, + { + "$id": "69", + "kind": "constant", + "name": "dictMethodsContentType", + "namespace": "", + "usage": "None", + "valueType": { + "$id": "70", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "value": "application/json", + "decorators": [] } ], "models": [ { - "$id": "69", + "$id": "71", "kind": "model", "name": "and", "namespace": "SpecialWords.Models", @@ -559,12 +575,12 @@ "decorators": [], "properties": [ { - "$id": "70", + "$id": "72", "kind": "property", "name": "name", "serializedName": "name", "type": { - "$id": "71", + "$id": "73", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -586,7 +602,7 @@ ] }, { - "$id": "72", + "$id": "74", "kind": "model", "name": "as", "namespace": "SpecialWords.Models", @@ -595,12 +611,12 @@ "decorators": [], "properties": [ { - "$id": "73", + "$id": "75", "kind": "property", "name": "name", "serializedName": "name", "type": { - "$id": "74", + "$id": "76", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -622,7 +638,7 @@ ] }, { - "$id": "75", + "$id": "77", "kind": "model", "name": "assert", "namespace": "SpecialWords.Models", @@ -631,12 +647,12 @@ "decorators": [], "properties": [ { - "$id": "76", + "$id": "78", "kind": "property", "name": "name", "serializedName": "name", "type": { - "$id": "77", + "$id": "79", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -658,7 +674,7 @@ ] }, { - "$id": "78", + "$id": "80", "kind": "model", "name": "async", "namespace": "SpecialWords.Models", @@ -667,12 +683,12 @@ "decorators": [], "properties": [ { - "$id": "79", + "$id": "81", "kind": "property", "name": "name", "serializedName": "name", "type": { - "$id": "80", + "$id": "82", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -694,7 +710,7 @@ ] }, { - "$id": "81", + "$id": "83", "kind": "model", "name": "await", "namespace": "SpecialWords.Models", @@ -703,12 +719,12 @@ "decorators": [], "properties": [ { - "$id": "82", + "$id": "84", "kind": "property", "name": "name", "serializedName": "name", "type": { - "$id": "83", + "$id": "85", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -730,7 +746,7 @@ ] }, { - "$id": "84", + "$id": "86", "kind": "model", "name": "break", "namespace": "SpecialWords.Models", @@ -739,12 +755,12 @@ "decorators": [], "properties": [ { - "$id": "85", + "$id": "87", "kind": "property", "name": "name", "serializedName": "name", "type": { - "$id": "86", + "$id": "88", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -766,7 +782,7 @@ ] }, { - "$id": "87", + "$id": "89", "kind": "model", "name": "class", "namespace": "SpecialWords.Models", @@ -775,12 +791,12 @@ "decorators": [], "properties": [ { - "$id": "88", + "$id": "90", "kind": "property", "name": "name", "serializedName": "name", "type": { - "$id": "89", + "$id": "91", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -802,7 +818,7 @@ ] }, { - "$id": "90", + "$id": "92", "kind": "model", "name": "constructor", "namespace": "SpecialWords.Models", @@ -811,12 +827,12 @@ "decorators": [], "properties": [ { - "$id": "91", + "$id": "93", "kind": "property", "name": "name", "serializedName": "name", "type": { - "$id": "92", + "$id": "94", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -838,7 +854,7 @@ ] }, { - "$id": "93", + "$id": "95", "kind": "model", "name": "continue", "namespace": "SpecialWords.Models", @@ -847,12 +863,12 @@ "decorators": [], "properties": [ { - "$id": "94", + "$id": "96", "kind": "property", "name": "name", "serializedName": "name", "type": { - "$id": "95", + "$id": "97", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -874,7 +890,7 @@ ] }, { - "$id": "96", + "$id": "98", "kind": "model", "name": "def", "namespace": "SpecialWords.Models", @@ -883,12 +899,12 @@ "decorators": [], "properties": [ { - "$id": "97", + "$id": "99", "kind": "property", "name": "name", "serializedName": "name", "type": { - "$id": "98", + "$id": "100", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -910,7 +926,7 @@ ] }, { - "$id": "99", + "$id": "101", "kind": "model", "name": "del", "namespace": "SpecialWords.Models", @@ -919,12 +935,12 @@ "decorators": [], "properties": [ { - "$id": "100", + "$id": "102", "kind": "property", "name": "name", "serializedName": "name", "type": { - "$id": "101", + "$id": "103", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -946,7 +962,7 @@ ] }, { - "$id": "102", + "$id": "104", "kind": "model", "name": "elif", "namespace": "SpecialWords.Models", @@ -955,12 +971,12 @@ "decorators": [], "properties": [ { - "$id": "103", + "$id": "105", "kind": "property", "name": "name", "serializedName": "name", "type": { - "$id": "104", + "$id": "106", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -982,7 +998,7 @@ ] }, { - "$id": "105", + "$id": "107", "kind": "model", "name": "else", "namespace": "SpecialWords.Models", @@ -991,12 +1007,12 @@ "decorators": [], "properties": [ { - "$id": "106", + "$id": "108", "kind": "property", "name": "name", "serializedName": "name", "type": { - "$id": "107", + "$id": "109", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1018,7 +1034,7 @@ ] }, { - "$id": "108", + "$id": "110", "kind": "model", "name": "except", "namespace": "SpecialWords.Models", @@ -1027,12 +1043,12 @@ "decorators": [], "properties": [ { - "$id": "109", + "$id": "111", "kind": "property", "name": "name", "serializedName": "name", "type": { - "$id": "110", + "$id": "112", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1054,7 +1070,7 @@ ] }, { - "$id": "111", + "$id": "113", "kind": "model", "name": "exec", "namespace": "SpecialWords.Models", @@ -1063,12 +1079,12 @@ "decorators": [], "properties": [ { - "$id": "112", + "$id": "114", "kind": "property", "name": "name", "serializedName": "name", "type": { - "$id": "113", + "$id": "115", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1090,7 +1106,7 @@ ] }, { - "$id": "114", + "$id": "116", "kind": "model", "name": "finally", "namespace": "SpecialWords.Models", @@ -1099,12 +1115,12 @@ "decorators": [], "properties": [ { - "$id": "115", + "$id": "117", "kind": "property", "name": "name", "serializedName": "name", "type": { - "$id": "116", + "$id": "118", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1126,7 +1142,7 @@ ] }, { - "$id": "117", + "$id": "119", "kind": "model", "name": "for", "namespace": "SpecialWords.Models", @@ -1135,12 +1151,12 @@ "decorators": [], "properties": [ { - "$id": "118", + "$id": "120", "kind": "property", "name": "name", "serializedName": "name", "type": { - "$id": "119", + "$id": "121", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1162,7 +1178,7 @@ ] }, { - "$id": "120", + "$id": "122", "kind": "model", "name": "from", "namespace": "SpecialWords.Models", @@ -1171,12 +1187,12 @@ "decorators": [], "properties": [ { - "$id": "121", + "$id": "123", "kind": "property", "name": "name", "serializedName": "name", "type": { - "$id": "122", + "$id": "124", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1198,7 +1214,7 @@ ] }, { - "$id": "123", + "$id": "125", "kind": "model", "name": "global", "namespace": "SpecialWords.Models", @@ -1207,12 +1223,12 @@ "decorators": [], "properties": [ { - "$id": "124", + "$id": "126", "kind": "property", "name": "name", "serializedName": "name", "type": { - "$id": "125", + "$id": "127", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1234,7 +1250,7 @@ ] }, { - "$id": "126", + "$id": "128", "kind": "model", "name": "if", "namespace": "SpecialWords.Models", @@ -1243,12 +1259,12 @@ "decorators": [], "properties": [ { - "$id": "127", + "$id": "129", "kind": "property", "name": "name", "serializedName": "name", "type": { - "$id": "128", + "$id": "130", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1270,7 +1286,7 @@ ] }, { - "$id": "129", + "$id": "131", "kind": "model", "name": "import", "namespace": "SpecialWords.Models", @@ -1279,12 +1295,12 @@ "decorators": [], "properties": [ { - "$id": "130", + "$id": "132", "kind": "property", "name": "name", "serializedName": "name", "type": { - "$id": "131", + "$id": "133", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1306,7 +1322,7 @@ ] }, { - "$id": "132", + "$id": "134", "kind": "model", "name": "in", "namespace": "SpecialWords.Models", @@ -1315,12 +1331,12 @@ "decorators": [], "properties": [ { - "$id": "133", + "$id": "135", "kind": "property", "name": "name", "serializedName": "name", "type": { - "$id": "134", + "$id": "136", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1342,7 +1358,7 @@ ] }, { - "$id": "135", + "$id": "137", "kind": "model", "name": "is", "namespace": "SpecialWords.Models", @@ -1351,12 +1367,12 @@ "decorators": [], "properties": [ { - "$id": "136", + "$id": "138", "kind": "property", "name": "name", "serializedName": "name", "type": { - "$id": "137", + "$id": "139", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1378,7 +1394,7 @@ ] }, { - "$id": "138", + "$id": "140", "kind": "model", "name": "lambda", "namespace": "SpecialWords.Models", @@ -1387,12 +1403,12 @@ "decorators": [], "properties": [ { - "$id": "139", + "$id": "141", "kind": "property", "name": "name", "serializedName": "name", "type": { - "$id": "140", + "$id": "142", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1414,7 +1430,7 @@ ] }, { - "$id": "141", + "$id": "143", "kind": "model", "name": "not", "namespace": "SpecialWords.Models", @@ -1423,12 +1439,12 @@ "decorators": [], "properties": [ { - "$id": "142", + "$id": "144", "kind": "property", "name": "name", "serializedName": "name", "type": { - "$id": "143", + "$id": "145", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1450,7 +1466,7 @@ ] }, { - "$id": "144", + "$id": "146", "kind": "model", "name": "or", "namespace": "SpecialWords.Models", @@ -1459,12 +1475,12 @@ "decorators": [], "properties": [ { - "$id": "145", + "$id": "147", "kind": "property", "name": "name", "serializedName": "name", "type": { - "$id": "146", + "$id": "148", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1486,7 +1502,7 @@ ] }, { - "$id": "147", + "$id": "149", "kind": "model", "name": "pass", "namespace": "SpecialWords.Models", @@ -1495,12 +1511,12 @@ "decorators": [], "properties": [ { - "$id": "148", + "$id": "150", "kind": "property", "name": "name", "serializedName": "name", "type": { - "$id": "149", + "$id": "151", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1522,7 +1538,7 @@ ] }, { - "$id": "150", + "$id": "152", "kind": "model", "name": "raise", "namespace": "SpecialWords.Models", @@ -1531,12 +1547,12 @@ "decorators": [], "properties": [ { - "$id": "151", + "$id": "153", "kind": "property", "name": "name", "serializedName": "name", "type": { - "$id": "152", + "$id": "154", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1558,7 +1574,7 @@ ] }, { - "$id": "153", + "$id": "155", "kind": "model", "name": "return", "namespace": "SpecialWords.Models", @@ -1567,12 +1583,12 @@ "decorators": [], "properties": [ { - "$id": "154", + "$id": "156", "kind": "property", "name": "name", "serializedName": "name", "type": { - "$id": "155", + "$id": "157", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1594,7 +1610,7 @@ ] }, { - "$id": "156", + "$id": "158", "kind": "model", "name": "try", "namespace": "SpecialWords.Models", @@ -1603,12 +1619,12 @@ "decorators": [], "properties": [ { - "$id": "157", + "$id": "159", "kind": "property", "name": "name", "serializedName": "name", "type": { - "$id": "158", + "$id": "160", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1630,7 +1646,7 @@ ] }, { - "$id": "159", + "$id": "161", "kind": "model", "name": "while", "namespace": "SpecialWords.Models", @@ -1639,12 +1655,12 @@ "decorators": [], "properties": [ { - "$id": "160", + "$id": "162", "kind": "property", "name": "name", "serializedName": "name", "type": { - "$id": "161", + "$id": "163", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1666,7 +1682,7 @@ ] }, { - "$id": "162", + "$id": "164", "kind": "model", "name": "with", "namespace": "SpecialWords.Models", @@ -1675,12 +1691,12 @@ "decorators": [], "properties": [ { - "$id": "163", + "$id": "165", "kind": "property", "name": "name", "serializedName": "name", "type": { - "$id": "164", + "$id": "166", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1702,7 +1718,7 @@ ] }, { - "$id": "165", + "$id": "167", "kind": "model", "name": "yield", "namespace": "SpecialWords.Models", @@ -1711,12 +1727,12 @@ "decorators": [], "properties": [ { - "$id": "166", + "$id": "168", "kind": "property", "name": "name", "serializedName": "name", "type": { - "$id": "167", + "$id": "169", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1738,7 +1754,7 @@ ] }, { - "$id": "168", + "$id": "170", "kind": "model", "name": "SameAsModel", "namespace": "SpecialWords.ModelProperties", @@ -1747,12 +1763,12 @@ "decorators": [], "properties": [ { - "$id": "169", + "$id": "171", "kind": "property", "name": "SameAsModel", "serializedName": "SameAsModel", "type": { - "$id": "170", + "$id": "172", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -1772,11 +1788,272 @@ "isHttpMetadata": false } ] + }, + { + "$id": "173", + "kind": "model", + "name": "DictMethods", + "namespace": "SpecialWords.ModelProperties", + "crossLanguageDefinitionId": "SpecialWords.ModelProperties.DictMethods", + "usage": "Input,Json", + "decorators": [], + "properties": [ + { + "$id": "174", + "kind": "property", + "name": "keys", + "serializedName": "keys", + "type": { + "$id": "175", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "optional": false, + "readOnly": false, + "discriminator": false, + "flatten": false, + "decorators": [], + "crossLanguageDefinitionId": "SpecialWords.ModelProperties.DictMethods.keys", + "serializationOptions": { + "json": { + "name": "keys" + } + }, + "isHttpMetadata": false + }, + { + "$id": "176", + "kind": "property", + "name": "items", + "serializedName": "items", + "type": { + "$id": "177", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "optional": false, + "readOnly": false, + "discriminator": false, + "flatten": false, + "decorators": [], + "crossLanguageDefinitionId": "SpecialWords.ModelProperties.DictMethods.items", + "serializationOptions": { + "json": { + "name": "items" + } + }, + "isHttpMetadata": false + }, + { + "$id": "178", + "kind": "property", + "name": "values", + "serializedName": "values", + "type": { + "$id": "179", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "optional": false, + "readOnly": false, + "discriminator": false, + "flatten": false, + "decorators": [], + "crossLanguageDefinitionId": "SpecialWords.ModelProperties.DictMethods.values", + "serializationOptions": { + "json": { + "name": "values" + } + }, + "isHttpMetadata": false + }, + { + "$id": "180", + "kind": "property", + "name": "popitem", + "serializedName": "popitem", + "type": { + "$id": "181", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "optional": false, + "readOnly": false, + "discriminator": false, + "flatten": false, + "decorators": [], + "crossLanguageDefinitionId": "SpecialWords.ModelProperties.DictMethods.popitem", + "serializationOptions": { + "json": { + "name": "popitem" + } + }, + "isHttpMetadata": false + }, + { + "$id": "182", + "kind": "property", + "name": "clear", + "serializedName": "clear", + "type": { + "$id": "183", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "optional": false, + "readOnly": false, + "discriminator": false, + "flatten": false, + "decorators": [], + "crossLanguageDefinitionId": "SpecialWords.ModelProperties.DictMethods.clear", + "serializationOptions": { + "json": { + "name": "clear" + } + }, + "isHttpMetadata": false + }, + { + "$id": "184", + "kind": "property", + "name": "update", + "serializedName": "update", + "type": { + "$id": "185", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "optional": false, + "readOnly": false, + "discriminator": false, + "flatten": false, + "decorators": [], + "crossLanguageDefinitionId": "SpecialWords.ModelProperties.DictMethods.update", + "serializationOptions": { + "json": { + "name": "update" + } + }, + "isHttpMetadata": false + }, + { + "$id": "186", + "kind": "property", + "name": "setdefault", + "serializedName": "setdefault", + "type": { + "$id": "187", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "optional": false, + "readOnly": false, + "discriminator": false, + "flatten": false, + "decorators": [], + "crossLanguageDefinitionId": "SpecialWords.ModelProperties.DictMethods.setdefault", + "serializationOptions": { + "json": { + "name": "setdefault" + } + }, + "isHttpMetadata": false + }, + { + "$id": "188", + "kind": "property", + "name": "pop", + "serializedName": "pop", + "type": { + "$id": "189", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "optional": false, + "readOnly": false, + "discriminator": false, + "flatten": false, + "decorators": [], + "crossLanguageDefinitionId": "SpecialWords.ModelProperties.DictMethods.pop", + "serializationOptions": { + "json": { + "name": "pop" + } + }, + "isHttpMetadata": false + }, + { + "$id": "190", + "kind": "property", + "name": "get", + "serializedName": "get", + "type": { + "$id": "191", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "optional": false, + "readOnly": false, + "discriminator": false, + "flatten": false, + "decorators": [], + "crossLanguageDefinitionId": "SpecialWords.ModelProperties.DictMethods.get", + "serializationOptions": { + "json": { + "name": "get" + } + }, + "isHttpMetadata": false + }, + { + "$id": "192", + "kind": "property", + "name": "copy", + "serializedName": "copy", + "type": { + "$id": "193", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "optional": false, + "readOnly": false, + "discriminator": false, + "flatten": false, + "decorators": [], + "crossLanguageDefinitionId": "SpecialWords.ModelProperties.DictMethods.copy", + "serializationOptions": { + "json": { + "name": "copy" + } + }, + "isHttpMetadata": false + } + ] } ], "clients": [ { - "$id": "171", + "$id": "194", "kind": "client", "name": "SpecialWordsClient", "namespace": "SpecialWords", @@ -1784,13 +2061,13 @@ "methods": [], "parameters": [ { - "$id": "172", + "$id": "195", "kind": "endpoint", "name": "endpoint", "serializedName": "endpoint", "doc": "Service host", "type": { - "$id": "173", + "$id": "196", "kind": "url", "name": "endpoint", "crossLanguageDefinitionId": "TypeSpec.url" @@ -1801,7 +2078,7 @@ "isEndpoint": true, "defaultValue": { "type": { - "$id": "174", + "$id": "197", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string" @@ -1820,26 +2097,26 @@ "apiVersions": [], "children": [ { - "$id": "175", + "$id": "198", "kind": "client", "name": "Models", "namespace": "SpecialWords.Models", "doc": "Verify model names", "methods": [ { - "$id": "176", + "$id": "199", "kind": "basic", "name": "withAnd", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "177", + "$id": "200", "name": "withAnd", "resourceName": "Models", "accessibility": "public", "parameters": [ { - "$id": "178", + "$id": "201", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -1856,12 +2133,12 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withAnd.contentType" }, { - "$id": "179", + "$id": "202", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$ref": "69" + "$ref": "71" }, "isApiVersion": false, "contentTypes": [ @@ -1898,12 +2175,12 @@ }, "parameters": [ { - "$id": "180", + "$id": "203", "kind": "method", "name": "body", "serializedName": "body", "type": { - "$ref": "69" + "$ref": "71" }, "location": "Body", "isApiVersion": false, @@ -1915,7 +2192,7 @@ "decorators": [] }, { - "$id": "181", + "$id": "204", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -1940,19 +2217,19 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withAnd" }, { - "$id": "182", + "$id": "205", "kind": "basic", "name": "withAs", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "183", + "$id": "206", "name": "withAs", "resourceName": "Models", "accessibility": "public", "parameters": [ { - "$id": "184", + "$id": "207", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -1969,12 +2246,12 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withAs.contentType" }, { - "$id": "185", + "$id": "208", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$ref": "72" + "$ref": "74" }, "isApiVersion": false, "contentTypes": [ @@ -2011,12 +2288,12 @@ }, "parameters": [ { - "$id": "186", + "$id": "209", "kind": "method", "name": "body", "serializedName": "body", "type": { - "$ref": "72" + "$ref": "74" }, "location": "Body", "isApiVersion": false, @@ -2028,7 +2305,7 @@ "decorators": [] }, { - "$id": "187", + "$id": "210", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -2053,19 +2330,19 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withAs" }, { - "$id": "188", + "$id": "211", "kind": "basic", "name": "withAssert", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "189", + "$id": "212", "name": "withAssert", "resourceName": "Models", "accessibility": "public", "parameters": [ { - "$id": "190", + "$id": "213", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -2082,12 +2359,12 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withAssert.contentType" }, { - "$id": "191", + "$id": "214", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$ref": "75" + "$ref": "77" }, "isApiVersion": false, "contentTypes": [ @@ -2124,12 +2401,12 @@ }, "parameters": [ { - "$id": "192", + "$id": "215", "kind": "method", "name": "body", "serializedName": "body", "type": { - "$ref": "75" + "$ref": "77" }, "location": "Body", "isApiVersion": false, @@ -2141,7 +2418,7 @@ "decorators": [] }, { - "$id": "193", + "$id": "216", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -2166,19 +2443,19 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withAssert" }, { - "$id": "194", + "$id": "217", "kind": "basic", "name": "withAsync", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "195", + "$id": "218", "name": "withAsync", "resourceName": "Models", "accessibility": "public", "parameters": [ { - "$id": "196", + "$id": "219", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -2195,12 +2472,12 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withAsync.contentType" }, { - "$id": "197", + "$id": "220", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$ref": "78" + "$ref": "80" }, "isApiVersion": false, "contentTypes": [ @@ -2237,12 +2514,12 @@ }, "parameters": [ { - "$id": "198", + "$id": "221", "kind": "method", "name": "body", "serializedName": "body", "type": { - "$ref": "78" + "$ref": "80" }, "location": "Body", "isApiVersion": false, @@ -2254,7 +2531,7 @@ "decorators": [] }, { - "$id": "199", + "$id": "222", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -2279,19 +2556,19 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withAsync" }, { - "$id": "200", + "$id": "223", "kind": "basic", "name": "withAwait", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "201", + "$id": "224", "name": "withAwait", "resourceName": "Models", "accessibility": "public", "parameters": [ { - "$id": "202", + "$id": "225", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -2308,12 +2585,12 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withAwait.contentType" }, { - "$id": "203", + "$id": "226", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$ref": "81" + "$ref": "83" }, "isApiVersion": false, "contentTypes": [ @@ -2350,12 +2627,12 @@ }, "parameters": [ { - "$id": "204", + "$id": "227", "kind": "method", "name": "body", "serializedName": "body", "type": { - "$ref": "81" + "$ref": "83" }, "location": "Body", "isApiVersion": false, @@ -2367,7 +2644,7 @@ "decorators": [] }, { - "$id": "205", + "$id": "228", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -2392,19 +2669,19 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withAwait" }, { - "$id": "206", + "$id": "229", "kind": "basic", "name": "withBreak", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "207", + "$id": "230", "name": "withBreak", "resourceName": "Models", "accessibility": "public", "parameters": [ { - "$id": "208", + "$id": "231", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -2421,12 +2698,12 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withBreak.contentType" }, { - "$id": "209", + "$id": "232", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$ref": "84" + "$ref": "86" }, "isApiVersion": false, "contentTypes": [ @@ -2463,12 +2740,12 @@ }, "parameters": [ { - "$id": "210", + "$id": "233", "kind": "method", "name": "body", "serializedName": "body", "type": { - "$ref": "84" + "$ref": "86" }, "location": "Body", "isApiVersion": false, @@ -2480,7 +2757,7 @@ "decorators": [] }, { - "$id": "211", + "$id": "234", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -2505,19 +2782,19 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withBreak" }, { - "$id": "212", + "$id": "235", "kind": "basic", "name": "withClass", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "213", + "$id": "236", "name": "withClass", "resourceName": "Models", "accessibility": "public", "parameters": [ { - "$id": "214", + "$id": "237", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -2534,12 +2811,12 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withClass.contentType" }, { - "$id": "215", + "$id": "238", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$ref": "87" + "$ref": "89" }, "isApiVersion": false, "contentTypes": [ @@ -2576,12 +2853,12 @@ }, "parameters": [ { - "$id": "216", + "$id": "239", "kind": "method", "name": "body", "serializedName": "body", "type": { - "$ref": "87" + "$ref": "89" }, "location": "Body", "isApiVersion": false, @@ -2593,7 +2870,7 @@ "decorators": [] }, { - "$id": "217", + "$id": "240", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -2618,19 +2895,19 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withClass" }, { - "$id": "218", + "$id": "241", "kind": "basic", "name": "withConstructor", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "219", + "$id": "242", "name": "withConstructor", "resourceName": "Models", "accessibility": "public", "parameters": [ { - "$id": "220", + "$id": "243", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -2647,12 +2924,12 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withConstructor.contentType" }, { - "$id": "221", + "$id": "244", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$ref": "90" + "$ref": "92" }, "isApiVersion": false, "contentTypes": [ @@ -2689,12 +2966,12 @@ }, "parameters": [ { - "$id": "222", + "$id": "245", "kind": "method", "name": "body", "serializedName": "body", "type": { - "$ref": "90" + "$ref": "92" }, "location": "Body", "isApiVersion": false, @@ -2706,7 +2983,7 @@ "decorators": [] }, { - "$id": "223", + "$id": "246", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -2731,19 +3008,19 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withConstructor" }, { - "$id": "224", + "$id": "247", "kind": "basic", "name": "withContinue", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "225", + "$id": "248", "name": "withContinue", "resourceName": "Models", "accessibility": "public", "parameters": [ { - "$id": "226", + "$id": "249", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -2760,12 +3037,12 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withContinue.contentType" }, { - "$id": "227", + "$id": "250", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$ref": "93" + "$ref": "95" }, "isApiVersion": false, "contentTypes": [ @@ -2802,12 +3079,12 @@ }, "parameters": [ { - "$id": "228", + "$id": "251", "kind": "method", "name": "body", "serializedName": "body", "type": { - "$ref": "93" + "$ref": "95" }, "location": "Body", "isApiVersion": false, @@ -2819,7 +3096,7 @@ "decorators": [] }, { - "$id": "229", + "$id": "252", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -2844,19 +3121,19 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withContinue" }, { - "$id": "230", + "$id": "253", "kind": "basic", "name": "withDef", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "231", + "$id": "254", "name": "withDef", "resourceName": "Models", "accessibility": "public", "parameters": [ { - "$id": "232", + "$id": "255", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -2873,12 +3150,12 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withDef.contentType" }, { - "$id": "233", + "$id": "256", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$ref": "96" + "$ref": "98" }, "isApiVersion": false, "contentTypes": [ @@ -2915,12 +3192,12 @@ }, "parameters": [ { - "$id": "234", + "$id": "257", "kind": "method", "name": "body", "serializedName": "body", "type": { - "$ref": "96" + "$ref": "98" }, "location": "Body", "isApiVersion": false, @@ -2932,7 +3209,7 @@ "decorators": [] }, { - "$id": "235", + "$id": "258", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -2957,19 +3234,19 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withDef" }, { - "$id": "236", + "$id": "259", "kind": "basic", "name": "withDel", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "237", + "$id": "260", "name": "withDel", "resourceName": "Models", "accessibility": "public", "parameters": [ { - "$id": "238", + "$id": "261", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -2986,12 +3263,12 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withDel.contentType" }, { - "$id": "239", + "$id": "262", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$ref": "99" + "$ref": "101" }, "isApiVersion": false, "contentTypes": [ @@ -3028,12 +3305,12 @@ }, "parameters": [ { - "$id": "240", + "$id": "263", "kind": "method", "name": "body", "serializedName": "body", "type": { - "$ref": "99" + "$ref": "101" }, "location": "Body", "isApiVersion": false, @@ -3045,7 +3322,7 @@ "decorators": [] }, { - "$id": "241", + "$id": "264", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -3070,19 +3347,19 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withDel" }, { - "$id": "242", + "$id": "265", "kind": "basic", "name": "withElif", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "243", + "$id": "266", "name": "withElif", "resourceName": "Models", "accessibility": "public", "parameters": [ { - "$id": "244", + "$id": "267", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -3099,12 +3376,12 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withElif.contentType" }, { - "$id": "245", + "$id": "268", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$ref": "102" + "$ref": "104" }, "isApiVersion": false, "contentTypes": [ @@ -3141,12 +3418,12 @@ }, "parameters": [ { - "$id": "246", + "$id": "269", "kind": "method", "name": "body", "serializedName": "body", "type": { - "$ref": "102" + "$ref": "104" }, "location": "Body", "isApiVersion": false, @@ -3158,7 +3435,7 @@ "decorators": [] }, { - "$id": "247", + "$id": "270", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -3183,19 +3460,19 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withElif" }, { - "$id": "248", + "$id": "271", "kind": "basic", "name": "withElse", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "249", + "$id": "272", "name": "withElse", "resourceName": "Models", "accessibility": "public", "parameters": [ { - "$id": "250", + "$id": "273", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -3212,12 +3489,12 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withElse.contentType" }, { - "$id": "251", + "$id": "274", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$ref": "105" + "$ref": "107" }, "isApiVersion": false, "contentTypes": [ @@ -3254,12 +3531,12 @@ }, "parameters": [ { - "$id": "252", + "$id": "275", "kind": "method", "name": "body", "serializedName": "body", "type": { - "$ref": "105" + "$ref": "107" }, "location": "Body", "isApiVersion": false, @@ -3271,7 +3548,7 @@ "decorators": [] }, { - "$id": "253", + "$id": "276", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -3296,19 +3573,19 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withElse" }, { - "$id": "254", + "$id": "277", "kind": "basic", "name": "withExcept", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "255", + "$id": "278", "name": "withExcept", "resourceName": "Models", "accessibility": "public", "parameters": [ { - "$id": "256", + "$id": "279", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -3325,12 +3602,12 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withExcept.contentType" }, { - "$id": "257", + "$id": "280", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$ref": "108" + "$ref": "110" }, "isApiVersion": false, "contentTypes": [ @@ -3367,12 +3644,12 @@ }, "parameters": [ { - "$id": "258", + "$id": "281", "kind": "method", "name": "body", "serializedName": "body", "type": { - "$ref": "108" + "$ref": "110" }, "location": "Body", "isApiVersion": false, @@ -3384,7 +3661,7 @@ "decorators": [] }, { - "$id": "259", + "$id": "282", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -3409,19 +3686,19 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withExcept" }, { - "$id": "260", + "$id": "283", "kind": "basic", "name": "withExec", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "261", + "$id": "284", "name": "withExec", "resourceName": "Models", "accessibility": "public", "parameters": [ { - "$id": "262", + "$id": "285", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -3438,12 +3715,12 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withExec.contentType" }, { - "$id": "263", + "$id": "286", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$ref": "111" + "$ref": "113" }, "isApiVersion": false, "contentTypes": [ @@ -3480,12 +3757,12 @@ }, "parameters": [ { - "$id": "264", + "$id": "287", "kind": "method", "name": "body", "serializedName": "body", "type": { - "$ref": "111" + "$ref": "113" }, "location": "Body", "isApiVersion": false, @@ -3497,7 +3774,7 @@ "decorators": [] }, { - "$id": "265", + "$id": "288", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -3522,19 +3799,19 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withExec" }, { - "$id": "266", + "$id": "289", "kind": "basic", "name": "withFinally", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "267", + "$id": "290", "name": "withFinally", "resourceName": "Models", "accessibility": "public", "parameters": [ { - "$id": "268", + "$id": "291", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -3551,12 +3828,12 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withFinally.contentType" }, { - "$id": "269", + "$id": "292", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$ref": "114" + "$ref": "116" }, "isApiVersion": false, "contentTypes": [ @@ -3593,12 +3870,12 @@ }, "parameters": [ { - "$id": "270", + "$id": "293", "kind": "method", "name": "body", "serializedName": "body", "type": { - "$ref": "114" + "$ref": "116" }, "location": "Body", "isApiVersion": false, @@ -3610,7 +3887,7 @@ "decorators": [] }, { - "$id": "271", + "$id": "294", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -3635,19 +3912,19 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withFinally" }, { - "$id": "272", + "$id": "295", "kind": "basic", "name": "withFor", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "273", + "$id": "296", "name": "withFor", "resourceName": "Models", "accessibility": "public", "parameters": [ { - "$id": "274", + "$id": "297", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -3664,12 +3941,12 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withFor.contentType" }, { - "$id": "275", + "$id": "298", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$ref": "117" + "$ref": "119" }, "isApiVersion": false, "contentTypes": [ @@ -3706,12 +3983,12 @@ }, "parameters": [ { - "$id": "276", + "$id": "299", "kind": "method", "name": "body", "serializedName": "body", "type": { - "$ref": "117" + "$ref": "119" }, "location": "Body", "isApiVersion": false, @@ -3723,7 +4000,7 @@ "decorators": [] }, { - "$id": "277", + "$id": "300", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -3748,19 +4025,19 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withFor" }, { - "$id": "278", + "$id": "301", "kind": "basic", "name": "withFrom", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "279", + "$id": "302", "name": "withFrom", "resourceName": "Models", "accessibility": "public", "parameters": [ { - "$id": "280", + "$id": "303", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -3777,12 +4054,12 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withFrom.contentType" }, { - "$id": "281", + "$id": "304", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$ref": "120" + "$ref": "122" }, "isApiVersion": false, "contentTypes": [ @@ -3819,12 +4096,12 @@ }, "parameters": [ { - "$id": "282", + "$id": "305", "kind": "method", "name": "body", "serializedName": "body", "type": { - "$ref": "120" + "$ref": "122" }, "location": "Body", "isApiVersion": false, @@ -3836,7 +4113,7 @@ "decorators": [] }, { - "$id": "283", + "$id": "306", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -3861,19 +4138,19 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withFrom" }, { - "$id": "284", + "$id": "307", "kind": "basic", "name": "withGlobal", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "285", + "$id": "308", "name": "withGlobal", "resourceName": "Models", "accessibility": "public", "parameters": [ { - "$id": "286", + "$id": "309", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -3890,12 +4167,12 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withGlobal.contentType" }, { - "$id": "287", + "$id": "310", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$ref": "123" + "$ref": "125" }, "isApiVersion": false, "contentTypes": [ @@ -3932,12 +4209,12 @@ }, "parameters": [ { - "$id": "288", + "$id": "311", "kind": "method", "name": "body", "serializedName": "body", "type": { - "$ref": "123" + "$ref": "125" }, "location": "Body", "isApiVersion": false, @@ -3949,7 +4226,7 @@ "decorators": [] }, { - "$id": "289", + "$id": "312", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -3974,19 +4251,19 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withGlobal" }, { - "$id": "290", + "$id": "313", "kind": "basic", "name": "withIf", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "291", + "$id": "314", "name": "withIf", "resourceName": "Models", "accessibility": "public", "parameters": [ { - "$id": "292", + "$id": "315", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -4003,12 +4280,12 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withIf.contentType" }, { - "$id": "293", + "$id": "316", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$ref": "126" + "$ref": "128" }, "isApiVersion": false, "contentTypes": [ @@ -4045,12 +4322,12 @@ }, "parameters": [ { - "$id": "294", + "$id": "317", "kind": "method", "name": "body", "serializedName": "body", "type": { - "$ref": "126" + "$ref": "128" }, "location": "Body", "isApiVersion": false, @@ -4062,7 +4339,7 @@ "decorators": [] }, { - "$id": "295", + "$id": "318", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -4087,19 +4364,19 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withIf" }, { - "$id": "296", + "$id": "319", "kind": "basic", "name": "withImport", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "297", + "$id": "320", "name": "withImport", "resourceName": "Models", "accessibility": "public", "parameters": [ { - "$id": "298", + "$id": "321", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -4116,12 +4393,12 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withImport.contentType" }, { - "$id": "299", + "$id": "322", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$ref": "129" + "$ref": "131" }, "isApiVersion": false, "contentTypes": [ @@ -4158,12 +4435,12 @@ }, "parameters": [ { - "$id": "300", + "$id": "323", "kind": "method", "name": "body", "serializedName": "body", "type": { - "$ref": "129" + "$ref": "131" }, "location": "Body", "isApiVersion": false, @@ -4175,7 +4452,7 @@ "decorators": [] }, { - "$id": "301", + "$id": "324", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -4200,19 +4477,19 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withImport" }, { - "$id": "302", + "$id": "325", "kind": "basic", "name": "withIn", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "303", + "$id": "326", "name": "withIn", "resourceName": "Models", "accessibility": "public", "parameters": [ { - "$id": "304", + "$id": "327", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -4229,12 +4506,12 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withIn.contentType" }, { - "$id": "305", + "$id": "328", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$ref": "132" + "$ref": "134" }, "isApiVersion": false, "contentTypes": [ @@ -4271,12 +4548,12 @@ }, "parameters": [ { - "$id": "306", + "$id": "329", "kind": "method", "name": "body", "serializedName": "body", "type": { - "$ref": "132" + "$ref": "134" }, "location": "Body", "isApiVersion": false, @@ -4288,7 +4565,7 @@ "decorators": [] }, { - "$id": "307", + "$id": "330", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -4313,19 +4590,19 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withIn" }, { - "$id": "308", + "$id": "331", "kind": "basic", "name": "withIs", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "309", + "$id": "332", "name": "withIs", "resourceName": "Models", "accessibility": "public", "parameters": [ { - "$id": "310", + "$id": "333", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -4342,12 +4619,12 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withIs.contentType" }, { - "$id": "311", + "$id": "334", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$ref": "135" + "$ref": "137" }, "isApiVersion": false, "contentTypes": [ @@ -4384,12 +4661,12 @@ }, "parameters": [ { - "$id": "312", + "$id": "335", "kind": "method", "name": "body", "serializedName": "body", "type": { - "$ref": "135" + "$ref": "137" }, "location": "Body", "isApiVersion": false, @@ -4401,7 +4678,7 @@ "decorators": [] }, { - "$id": "313", + "$id": "336", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -4426,19 +4703,19 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withIs" }, { - "$id": "314", + "$id": "337", "kind": "basic", "name": "withLambda", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "315", + "$id": "338", "name": "withLambda", "resourceName": "Models", "accessibility": "public", "parameters": [ { - "$id": "316", + "$id": "339", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -4455,12 +4732,12 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withLambda.contentType" }, { - "$id": "317", + "$id": "340", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$ref": "138" + "$ref": "140" }, "isApiVersion": false, "contentTypes": [ @@ -4497,12 +4774,12 @@ }, "parameters": [ { - "$id": "318", + "$id": "341", "kind": "method", "name": "body", "serializedName": "body", "type": { - "$ref": "138" + "$ref": "140" }, "location": "Body", "isApiVersion": false, @@ -4514,7 +4791,7 @@ "decorators": [] }, { - "$id": "319", + "$id": "342", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -4539,19 +4816,19 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withLambda" }, { - "$id": "320", + "$id": "343", "kind": "basic", "name": "withNot", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "321", + "$id": "344", "name": "withNot", "resourceName": "Models", "accessibility": "public", "parameters": [ { - "$id": "322", + "$id": "345", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -4568,12 +4845,12 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withNot.contentType" }, { - "$id": "323", + "$id": "346", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$ref": "141" + "$ref": "143" }, "isApiVersion": false, "contentTypes": [ @@ -4610,12 +4887,12 @@ }, "parameters": [ { - "$id": "324", + "$id": "347", "kind": "method", "name": "body", "serializedName": "body", "type": { - "$ref": "141" + "$ref": "143" }, "location": "Body", "isApiVersion": false, @@ -4627,7 +4904,7 @@ "decorators": [] }, { - "$id": "325", + "$id": "348", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -4652,19 +4929,19 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withNot" }, { - "$id": "326", + "$id": "349", "kind": "basic", "name": "withOr", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "327", + "$id": "350", "name": "withOr", "resourceName": "Models", "accessibility": "public", "parameters": [ { - "$id": "328", + "$id": "351", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -4681,12 +4958,12 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withOr.contentType" }, { - "$id": "329", + "$id": "352", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$ref": "144" + "$ref": "146" }, "isApiVersion": false, "contentTypes": [ @@ -4723,12 +5000,12 @@ }, "parameters": [ { - "$id": "330", + "$id": "353", "kind": "method", "name": "body", "serializedName": "body", "type": { - "$ref": "144" + "$ref": "146" }, "location": "Body", "isApiVersion": false, @@ -4740,7 +5017,7 @@ "decorators": [] }, { - "$id": "331", + "$id": "354", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -4765,19 +5042,19 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withOr" }, { - "$id": "332", + "$id": "355", "kind": "basic", "name": "withPass", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "333", + "$id": "356", "name": "withPass", "resourceName": "Models", "accessibility": "public", "parameters": [ { - "$id": "334", + "$id": "357", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -4794,12 +5071,12 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withPass.contentType" }, { - "$id": "335", + "$id": "358", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$ref": "147" + "$ref": "149" }, "isApiVersion": false, "contentTypes": [ @@ -4836,12 +5113,12 @@ }, "parameters": [ { - "$id": "336", + "$id": "359", "kind": "method", "name": "body", "serializedName": "body", "type": { - "$ref": "147" + "$ref": "149" }, "location": "Body", "isApiVersion": false, @@ -4853,7 +5130,7 @@ "decorators": [] }, { - "$id": "337", + "$id": "360", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -4878,19 +5155,19 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withPass" }, { - "$id": "338", + "$id": "361", "kind": "basic", "name": "withRaise", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "339", + "$id": "362", "name": "withRaise", "resourceName": "Models", "accessibility": "public", "parameters": [ { - "$id": "340", + "$id": "363", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -4907,12 +5184,12 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withRaise.contentType" }, { - "$id": "341", + "$id": "364", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$ref": "150" + "$ref": "152" }, "isApiVersion": false, "contentTypes": [ @@ -4949,12 +5226,12 @@ }, "parameters": [ { - "$id": "342", + "$id": "365", "kind": "method", "name": "body", "serializedName": "body", "type": { - "$ref": "150" + "$ref": "152" }, "location": "Body", "isApiVersion": false, @@ -4966,7 +5243,7 @@ "decorators": [] }, { - "$id": "343", + "$id": "366", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -4991,19 +5268,19 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withRaise" }, { - "$id": "344", + "$id": "367", "kind": "basic", "name": "withReturn", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "345", + "$id": "368", "name": "withReturn", "resourceName": "Models", "accessibility": "public", "parameters": [ { - "$id": "346", + "$id": "369", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -5020,12 +5297,12 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withReturn.contentType" }, { - "$id": "347", + "$id": "370", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$ref": "153" + "$ref": "155" }, "isApiVersion": false, "contentTypes": [ @@ -5062,12 +5339,12 @@ }, "parameters": [ { - "$id": "348", + "$id": "371", "kind": "method", "name": "body", "serializedName": "body", "type": { - "$ref": "153" + "$ref": "155" }, "location": "Body", "isApiVersion": false, @@ -5079,7 +5356,7 @@ "decorators": [] }, { - "$id": "349", + "$id": "372", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -5104,19 +5381,19 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withReturn" }, { - "$id": "350", + "$id": "373", "kind": "basic", "name": "withTry", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "351", + "$id": "374", "name": "withTry", "resourceName": "Models", "accessibility": "public", "parameters": [ { - "$id": "352", + "$id": "375", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -5133,12 +5410,12 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withTry.contentType" }, { - "$id": "353", + "$id": "376", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$ref": "156" + "$ref": "158" }, "isApiVersion": false, "contentTypes": [ @@ -5175,12 +5452,12 @@ }, "parameters": [ { - "$id": "354", + "$id": "377", "kind": "method", "name": "body", "serializedName": "body", "type": { - "$ref": "156" + "$ref": "158" }, "location": "Body", "isApiVersion": false, @@ -5192,7 +5469,7 @@ "decorators": [] }, { - "$id": "355", + "$id": "378", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -5217,19 +5494,19 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withTry" }, { - "$id": "356", + "$id": "379", "kind": "basic", "name": "withWhile", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "357", + "$id": "380", "name": "withWhile", "resourceName": "Models", "accessibility": "public", "parameters": [ { - "$id": "358", + "$id": "381", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -5246,12 +5523,12 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withWhile.contentType" }, { - "$id": "359", + "$id": "382", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$ref": "159" + "$ref": "161" }, "isApiVersion": false, "contentTypes": [ @@ -5288,12 +5565,12 @@ }, "parameters": [ { - "$id": "360", + "$id": "383", "kind": "method", "name": "body", "serializedName": "body", "type": { - "$ref": "159" + "$ref": "161" }, "location": "Body", "isApiVersion": false, @@ -5305,7 +5582,7 @@ "decorators": [] }, { - "$id": "361", + "$id": "384", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -5330,19 +5607,19 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withWhile" }, { - "$id": "362", + "$id": "385", "kind": "basic", "name": "withWith", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "363", + "$id": "386", "name": "withWith", "resourceName": "Models", "accessibility": "public", "parameters": [ { - "$id": "364", + "$id": "387", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -5359,12 +5636,12 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withWith.contentType" }, { - "$id": "365", + "$id": "388", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$ref": "162" + "$ref": "164" }, "isApiVersion": false, "contentTypes": [ @@ -5401,12 +5678,12 @@ }, "parameters": [ { - "$id": "366", + "$id": "389", "kind": "method", "name": "body", "serializedName": "body", "type": { - "$ref": "162" + "$ref": "164" }, "location": "Body", "isApiVersion": false, @@ -5418,7 +5695,7 @@ "decorators": [] }, { - "$id": "367", + "$id": "390", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -5443,19 +5720,19 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withWith" }, { - "$id": "368", + "$id": "391", "kind": "basic", "name": "withYield", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "369", + "$id": "392", "name": "withYield", "resourceName": "Models", "accessibility": "public", "parameters": [ { - "$id": "370", + "$id": "393", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -5472,12 +5749,12 @@ "crossLanguageDefinitionId": "SpecialWords.Models.withYield.contentType" }, { - "$id": "371", + "$id": "394", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$ref": "165" + "$ref": "167" }, "isApiVersion": false, "contentTypes": [ @@ -5514,12 +5791,12 @@ }, "parameters": [ { - "$id": "372", + "$id": "395", "kind": "method", "name": "body", "serializedName": "body", "type": { - "$ref": "165" + "$ref": "167" }, "location": "Body", "isApiVersion": false, @@ -5531,7 +5808,7 @@ "decorators": [] }, { - "$id": "373", + "$id": "396", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -5558,13 +5835,13 @@ ], "parameters": [ { - "$id": "374", + "$id": "397", "kind": "endpoint", "name": "endpoint", "serializedName": "endpoint", "doc": "Service host", "type": { - "$id": "375", + "$id": "398", "kind": "url", "name": "endpoint", "crossLanguageDefinitionId": "TypeSpec.url" @@ -5575,7 +5852,7 @@ "isEndpoint": true, "defaultValue": { "type": { - "$id": "376", + "$id": "399", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string" @@ -5593,30 +5870,30 @@ "crossLanguageDefinitionId": "SpecialWords.Models", "apiVersions": [], "parent": { - "$ref": "171" + "$ref": "194" } }, { - "$id": "377", + "$id": "400", "kind": "client", "name": "ModelProperties", "namespace": "SpecialWords.ModelProperties", "doc": "Verify model names", "methods": [ { - "$id": "378", + "$id": "401", "kind": "basic", "name": "sameAsModel", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "379", + "$id": "402", "name": "sameAsModel", "resourceName": "ModelProperties", "accessibility": "public", "parameters": [ { - "$id": "380", + "$id": "403", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -5633,12 +5910,12 @@ "crossLanguageDefinitionId": "SpecialWords.ModelProperties.sameAsModel.contentType" }, { - "$id": "381", + "$id": "404", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$ref": "168" + "$ref": "170" }, "isApiVersion": false, "contentTypes": [ @@ -5675,12 +5952,12 @@ }, "parameters": [ { - "$id": "382", + "$id": "405", "kind": "method", "name": "body", "serializedName": "body", "type": { - "$ref": "168" + "$ref": "170" }, "location": "Body", "isApiVersion": false, @@ -5692,7 +5969,7 @@ "decorators": [] }, { - "$id": "383", + "$id": "406", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -5715,17 +5992,130 @@ "generateConvenient": true, "generateProtocol": true, "crossLanguageDefinitionId": "SpecialWords.ModelProperties.sameAsModel" + }, + { + "$id": "407", + "kind": "basic", + "name": "dictMethods", + "accessibility": "public", + "apiVersions": [], + "operation": { + "$id": "408", + "name": "dictMethods", + "resourceName": "ModelProperties", + "accessibility": "public", + "parameters": [ + { + "$id": "409", + "kind": "header", + "name": "contentType", + "serializedName": "Content-Type", + "doc": "Body parameter's content type. Known values are application/json", + "type": { + "$ref": "69" + }, + "isApiVersion": false, + "optional": false, + "isContentType": true, + "scope": "Constant", + "readOnly": false, + "decorators": [], + "crossLanguageDefinitionId": "SpecialWords.ModelProperties.dictMethods.contentType" + }, + { + "$id": "410", + "kind": "body", + "name": "body", + "serializedName": "body", + "type": { + "$ref": "173" + }, + "isApiVersion": false, + "contentTypes": [ + "application/json" + ], + "defaultContentType": "application/json", + "optional": false, + "scope": "Method", + "decorators": [], + "readOnly": false, + "crossLanguageDefinitionId": "SpecialWords.ModelProperties.dictMethods.body" + } + ], + "responses": [ + { + "statusCodes": [ + 204 + ], + "headers": [], + "isErrorResponse": false + } + ], + "httpMethod": "POST", + "uri": "{endpoint}", + "path": "/special-words/model-properties/dict-methods", + "requestMediaTypes": [ + "application/json" + ], + "bufferResponse": true, + "generateProtocolMethod": true, + "generateConvenienceMethod": true, + "crossLanguageDefinitionId": "SpecialWords.ModelProperties.dictMethods", + "decorators": [] + }, + "parameters": [ + { + "$id": "411", + "kind": "method", + "name": "body", + "serializedName": "body", + "type": { + "$ref": "173" + }, + "location": "Body", + "isApiVersion": false, + "optional": false, + "scope": "Method", + "crossLanguageDefinitionId": "SpecialWords.ModelProperties.dictMethods.body", + "readOnly": false, + "access": "public", + "decorators": [] + }, + { + "$id": "412", + "kind": "method", + "name": "contentType", + "serializedName": "Content-Type", + "doc": "Body parameter's content type. Known values are application/json", + "type": { + "$ref": "69" + }, + "location": "Header", + "isApiVersion": false, + "optional": false, + "scope": "Constant", + "crossLanguageDefinitionId": "SpecialWords.ModelProperties.dictMethods.contentType", + "readOnly": false, + "access": "public", + "decorators": [] + } + ], + "response": {}, + "isOverride": false, + "generateConvenient": true, + "generateProtocol": true, + "crossLanguageDefinitionId": "SpecialWords.ModelProperties.dictMethods" } ], "parameters": [ { - "$id": "384", + "$id": "413", "kind": "endpoint", "name": "endpoint", "serializedName": "endpoint", "doc": "Service host", "type": { - "$id": "385", + "$id": "414", "kind": "url", "name": "endpoint", "crossLanguageDefinitionId": "TypeSpec.url" @@ -5736,7 +6126,7 @@ "isEndpoint": true, "defaultValue": { "type": { - "$id": "386", + "$id": "415", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string" @@ -5754,24 +6144,24 @@ "crossLanguageDefinitionId": "SpecialWords.ModelProperties", "apiVersions": [], "parent": { - "$ref": "171" + "$ref": "194" } }, { - "$id": "387", + "$id": "416", "kind": "client", "name": "Operations", "namespace": "SpecialWords", "doc": "Test reserved words as operation name.", "methods": [ { - "$id": "388", + "$id": "417", "kind": "basic", "name": "and", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "389", + "$id": "418", "name": "and", "resourceName": "Operations", "accessibility": "public", @@ -5802,13 +6192,13 @@ "crossLanguageDefinitionId": "SpecialWords.Operations.and" }, { - "$id": "390", + "$id": "419", "kind": "basic", "name": "as", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "391", + "$id": "420", "name": "as", "resourceName": "Operations", "accessibility": "public", @@ -5839,13 +6229,13 @@ "crossLanguageDefinitionId": "SpecialWords.Operations.as" }, { - "$id": "392", + "$id": "421", "kind": "basic", "name": "assert", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "393", + "$id": "422", "name": "assert", "resourceName": "Operations", "accessibility": "public", @@ -5876,13 +6266,13 @@ "crossLanguageDefinitionId": "SpecialWords.Operations.assert" }, { - "$id": "394", + "$id": "423", "kind": "basic", "name": "async", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "395", + "$id": "424", "name": "async", "resourceName": "Operations", "accessibility": "public", @@ -5913,13 +6303,13 @@ "crossLanguageDefinitionId": "SpecialWords.Operations.async" }, { - "$id": "396", + "$id": "425", "kind": "basic", "name": "await", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "397", + "$id": "426", "name": "await", "resourceName": "Operations", "accessibility": "public", @@ -5950,13 +6340,13 @@ "crossLanguageDefinitionId": "SpecialWords.Operations.await" }, { - "$id": "398", + "$id": "427", "kind": "basic", "name": "break", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "399", + "$id": "428", "name": "break", "resourceName": "Operations", "accessibility": "public", @@ -5987,13 +6377,13 @@ "crossLanguageDefinitionId": "SpecialWords.Operations.break" }, { - "$id": "400", + "$id": "429", "kind": "basic", "name": "class", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "401", + "$id": "430", "name": "class", "resourceName": "Operations", "accessibility": "public", @@ -6024,13 +6414,13 @@ "crossLanguageDefinitionId": "SpecialWords.Operations.class" }, { - "$id": "402", + "$id": "431", "kind": "basic", "name": "constructor", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "403", + "$id": "432", "name": "constructor", "resourceName": "Operations", "accessibility": "public", @@ -6061,13 +6451,13 @@ "crossLanguageDefinitionId": "SpecialWords.Operations.constructor" }, { - "$id": "404", + "$id": "433", "kind": "basic", "name": "continue", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "405", + "$id": "434", "name": "continue", "resourceName": "Operations", "accessibility": "public", @@ -6098,13 +6488,13 @@ "crossLanguageDefinitionId": "SpecialWords.Operations.continue" }, { - "$id": "406", + "$id": "435", "kind": "basic", "name": "def", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "407", + "$id": "436", "name": "def", "resourceName": "Operations", "accessibility": "public", @@ -6135,13 +6525,13 @@ "crossLanguageDefinitionId": "SpecialWords.Operations.def" }, { - "$id": "408", + "$id": "437", "kind": "basic", "name": "del", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "409", + "$id": "438", "name": "del", "resourceName": "Operations", "accessibility": "public", @@ -6172,13 +6562,13 @@ "crossLanguageDefinitionId": "SpecialWords.Operations.del" }, { - "$id": "410", + "$id": "439", "kind": "basic", "name": "elif", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "411", + "$id": "440", "name": "elif", "resourceName": "Operations", "accessibility": "public", @@ -6209,13 +6599,13 @@ "crossLanguageDefinitionId": "SpecialWords.Operations.elif" }, { - "$id": "412", + "$id": "441", "kind": "basic", "name": "else", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "413", + "$id": "442", "name": "else", "resourceName": "Operations", "accessibility": "public", @@ -6246,13 +6636,13 @@ "crossLanguageDefinitionId": "SpecialWords.Operations.else" }, { - "$id": "414", + "$id": "443", "kind": "basic", "name": "except", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "415", + "$id": "444", "name": "except", "resourceName": "Operations", "accessibility": "public", @@ -6283,13 +6673,13 @@ "crossLanguageDefinitionId": "SpecialWords.Operations.except" }, { - "$id": "416", + "$id": "445", "kind": "basic", "name": "exec", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "417", + "$id": "446", "name": "exec", "resourceName": "Operations", "accessibility": "public", @@ -6320,13 +6710,13 @@ "crossLanguageDefinitionId": "SpecialWords.Operations.exec" }, { - "$id": "418", + "$id": "447", "kind": "basic", "name": "finally", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "419", + "$id": "448", "name": "finally", "resourceName": "Operations", "accessibility": "public", @@ -6357,13 +6747,13 @@ "crossLanguageDefinitionId": "SpecialWords.Operations.finally" }, { - "$id": "420", + "$id": "449", "kind": "basic", "name": "for", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "421", + "$id": "450", "name": "for", "resourceName": "Operations", "accessibility": "public", @@ -6394,13 +6784,13 @@ "crossLanguageDefinitionId": "SpecialWords.Operations.for" }, { - "$id": "422", + "$id": "451", "kind": "basic", "name": "from", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "423", + "$id": "452", "name": "from", "resourceName": "Operations", "accessibility": "public", @@ -6431,13 +6821,13 @@ "crossLanguageDefinitionId": "SpecialWords.Operations.from" }, { - "$id": "424", + "$id": "453", "kind": "basic", "name": "global", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "425", + "$id": "454", "name": "global", "resourceName": "Operations", "accessibility": "public", @@ -6468,13 +6858,13 @@ "crossLanguageDefinitionId": "SpecialWords.Operations.global" }, { - "$id": "426", + "$id": "455", "kind": "basic", "name": "if", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "427", + "$id": "456", "name": "if", "resourceName": "Operations", "accessibility": "public", @@ -6505,13 +6895,13 @@ "crossLanguageDefinitionId": "SpecialWords.Operations.if" }, { - "$id": "428", + "$id": "457", "kind": "basic", "name": "import", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "429", + "$id": "458", "name": "import", "resourceName": "Operations", "accessibility": "public", @@ -6542,13 +6932,13 @@ "crossLanguageDefinitionId": "SpecialWords.Operations.import" }, { - "$id": "430", + "$id": "459", "kind": "basic", "name": "in", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "431", + "$id": "460", "name": "in", "resourceName": "Operations", "accessibility": "public", @@ -6579,13 +6969,13 @@ "crossLanguageDefinitionId": "SpecialWords.Operations.in" }, { - "$id": "432", + "$id": "461", "kind": "basic", "name": "is", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "433", + "$id": "462", "name": "is", "resourceName": "Operations", "accessibility": "public", @@ -6616,13 +7006,13 @@ "crossLanguageDefinitionId": "SpecialWords.Operations.is" }, { - "$id": "434", + "$id": "463", "kind": "basic", "name": "lambda", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "435", + "$id": "464", "name": "lambda", "resourceName": "Operations", "accessibility": "public", @@ -6653,13 +7043,13 @@ "crossLanguageDefinitionId": "SpecialWords.Operations.lambda" }, { - "$id": "436", + "$id": "465", "kind": "basic", "name": "not", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "437", + "$id": "466", "name": "not", "resourceName": "Operations", "accessibility": "public", @@ -6690,13 +7080,13 @@ "crossLanguageDefinitionId": "SpecialWords.Operations.not" }, { - "$id": "438", + "$id": "467", "kind": "basic", "name": "or", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "439", + "$id": "468", "name": "or", "resourceName": "Operations", "accessibility": "public", @@ -6727,13 +7117,13 @@ "crossLanguageDefinitionId": "SpecialWords.Operations.or" }, { - "$id": "440", + "$id": "469", "kind": "basic", "name": "pass", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "441", + "$id": "470", "name": "pass", "resourceName": "Operations", "accessibility": "public", @@ -6764,13 +7154,13 @@ "crossLanguageDefinitionId": "SpecialWords.Operations.pass" }, { - "$id": "442", + "$id": "471", "kind": "basic", "name": "raise", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "443", + "$id": "472", "name": "raise", "resourceName": "Operations", "accessibility": "public", @@ -6801,13 +7191,13 @@ "crossLanguageDefinitionId": "SpecialWords.Operations.raise" }, { - "$id": "444", + "$id": "473", "kind": "basic", "name": "return", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "445", + "$id": "474", "name": "return", "resourceName": "Operations", "accessibility": "public", @@ -6838,13 +7228,13 @@ "crossLanguageDefinitionId": "SpecialWords.Operations.return" }, { - "$id": "446", + "$id": "475", "kind": "basic", "name": "try", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "447", + "$id": "476", "name": "try", "resourceName": "Operations", "accessibility": "public", @@ -6875,13 +7265,13 @@ "crossLanguageDefinitionId": "SpecialWords.Operations.try" }, { - "$id": "448", + "$id": "477", "kind": "basic", "name": "while", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "449", + "$id": "478", "name": "while", "resourceName": "Operations", "accessibility": "public", @@ -6912,13 +7302,13 @@ "crossLanguageDefinitionId": "SpecialWords.Operations.while" }, { - "$id": "450", + "$id": "479", "kind": "basic", "name": "with", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "451", + "$id": "480", "name": "with", "resourceName": "Operations", "accessibility": "public", @@ -6949,13 +7339,13 @@ "crossLanguageDefinitionId": "SpecialWords.Operations.with" }, { - "$id": "452", + "$id": "481", "kind": "basic", "name": "yield", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "453", + "$id": "482", "name": "yield", "resourceName": "Operations", "accessibility": "public", @@ -6988,13 +7378,13 @@ ], "parameters": [ { - "$id": "454", + "$id": "483", "kind": "endpoint", "name": "endpoint", "serializedName": "endpoint", "doc": "Service host", "type": { - "$id": "455", + "$id": "484", "kind": "url", "name": "endpoint", "crossLanguageDefinitionId": "TypeSpec.url" @@ -7005,7 +7395,7 @@ "isEndpoint": true, "defaultValue": { "type": { - "$id": "456", + "$id": "485", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string" @@ -7023,35 +7413,35 @@ "crossLanguageDefinitionId": "SpecialWords.Operations", "apiVersions": [], "parent": { - "$ref": "171" + "$ref": "194" } }, { - "$id": "457", + "$id": "486", "kind": "client", "name": "Parameters", "namespace": "SpecialWords", "doc": "Verify reserved words as parameter name.", "methods": [ { - "$id": "458", + "$id": "487", "kind": "basic", "name": "withAnd", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "459", + "$id": "488", "name": "withAnd", "resourceName": "Parameters", "accessibility": "public", "parameters": [ { - "$id": "460", + "$id": "489", "kind": "query", "name": "and", "serializedName": "and", "type": { - "$id": "461", + "$id": "490", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -7086,12 +7476,12 @@ }, "parameters": [ { - "$id": "462", + "$id": "491", "kind": "method", "name": "and", "serializedName": "and", "type": { - "$id": "463", + "$id": "492", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -7114,24 +7504,24 @@ "crossLanguageDefinitionId": "SpecialWords.Parameters.withAnd" }, { - "$id": "464", + "$id": "493", "kind": "basic", "name": "withAs", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "465", + "$id": "494", "name": "withAs", "resourceName": "Parameters", "accessibility": "public", "parameters": [ { - "$id": "466", + "$id": "495", "kind": "query", "name": "as", "serializedName": "as", "type": { - "$id": "467", + "$id": "496", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -7166,12 +7556,12 @@ }, "parameters": [ { - "$id": "468", + "$id": "497", "kind": "method", "name": "as", "serializedName": "as", "type": { - "$id": "469", + "$id": "498", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -7194,24 +7584,24 @@ "crossLanguageDefinitionId": "SpecialWords.Parameters.withAs" }, { - "$id": "470", + "$id": "499", "kind": "basic", "name": "withAssert", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "471", + "$id": "500", "name": "withAssert", "resourceName": "Parameters", "accessibility": "public", "parameters": [ { - "$id": "472", + "$id": "501", "kind": "query", "name": "assert", "serializedName": "assert", "type": { - "$id": "473", + "$id": "502", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -7246,12 +7636,12 @@ }, "parameters": [ { - "$id": "474", + "$id": "503", "kind": "method", "name": "assert", "serializedName": "assert", "type": { - "$id": "475", + "$id": "504", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -7274,24 +7664,24 @@ "crossLanguageDefinitionId": "SpecialWords.Parameters.withAssert" }, { - "$id": "476", + "$id": "505", "kind": "basic", "name": "withAsync", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "477", + "$id": "506", "name": "withAsync", "resourceName": "Parameters", "accessibility": "public", "parameters": [ { - "$id": "478", + "$id": "507", "kind": "query", "name": "async", "serializedName": "async", "type": { - "$id": "479", + "$id": "508", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -7326,12 +7716,12 @@ }, "parameters": [ { - "$id": "480", + "$id": "509", "kind": "method", "name": "async", "serializedName": "async", "type": { - "$id": "481", + "$id": "510", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -7354,24 +7744,24 @@ "crossLanguageDefinitionId": "SpecialWords.Parameters.withAsync" }, { - "$id": "482", + "$id": "511", "kind": "basic", "name": "withAwait", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "483", + "$id": "512", "name": "withAwait", "resourceName": "Parameters", "accessibility": "public", "parameters": [ { - "$id": "484", + "$id": "513", "kind": "query", "name": "await", "serializedName": "await", "type": { - "$id": "485", + "$id": "514", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -7406,12 +7796,12 @@ }, "parameters": [ { - "$id": "486", + "$id": "515", "kind": "method", "name": "await", "serializedName": "await", "type": { - "$id": "487", + "$id": "516", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -7434,24 +7824,24 @@ "crossLanguageDefinitionId": "SpecialWords.Parameters.withAwait" }, { - "$id": "488", + "$id": "517", "kind": "basic", "name": "withBreak", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "489", + "$id": "518", "name": "withBreak", "resourceName": "Parameters", "accessibility": "public", "parameters": [ { - "$id": "490", + "$id": "519", "kind": "query", "name": "break", "serializedName": "break", "type": { - "$id": "491", + "$id": "520", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -7486,12 +7876,12 @@ }, "parameters": [ { - "$id": "492", + "$id": "521", "kind": "method", "name": "break", "serializedName": "break", "type": { - "$id": "493", + "$id": "522", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -7514,24 +7904,24 @@ "crossLanguageDefinitionId": "SpecialWords.Parameters.withBreak" }, { - "$id": "494", + "$id": "523", "kind": "basic", "name": "withClass", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "495", + "$id": "524", "name": "withClass", "resourceName": "Parameters", "accessibility": "public", "parameters": [ { - "$id": "496", + "$id": "525", "kind": "query", "name": "class", "serializedName": "class", "type": { - "$id": "497", + "$id": "526", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -7566,12 +7956,12 @@ }, "parameters": [ { - "$id": "498", + "$id": "527", "kind": "method", "name": "class", "serializedName": "class", "type": { - "$id": "499", + "$id": "528", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -7594,24 +7984,24 @@ "crossLanguageDefinitionId": "SpecialWords.Parameters.withClass" }, { - "$id": "500", + "$id": "529", "kind": "basic", "name": "withConstructor", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "501", + "$id": "530", "name": "withConstructor", "resourceName": "Parameters", "accessibility": "public", "parameters": [ { - "$id": "502", + "$id": "531", "kind": "query", "name": "constructor", "serializedName": "constructor", "type": { - "$id": "503", + "$id": "532", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -7646,12 +8036,12 @@ }, "parameters": [ { - "$id": "504", + "$id": "533", "kind": "method", "name": "constructor", "serializedName": "constructor", "type": { - "$id": "505", + "$id": "534", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -7674,24 +8064,24 @@ "crossLanguageDefinitionId": "SpecialWords.Parameters.withConstructor" }, { - "$id": "506", + "$id": "535", "kind": "basic", "name": "withContinue", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "507", + "$id": "536", "name": "withContinue", "resourceName": "Parameters", "accessibility": "public", "parameters": [ { - "$id": "508", + "$id": "537", "kind": "query", "name": "continue", "serializedName": "continue", "type": { - "$id": "509", + "$id": "538", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -7726,12 +8116,12 @@ }, "parameters": [ { - "$id": "510", + "$id": "539", "kind": "method", "name": "continue", "serializedName": "continue", "type": { - "$id": "511", + "$id": "540", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -7754,24 +8144,24 @@ "crossLanguageDefinitionId": "SpecialWords.Parameters.withContinue" }, { - "$id": "512", + "$id": "541", "kind": "basic", "name": "withDef", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "513", + "$id": "542", "name": "withDef", "resourceName": "Parameters", "accessibility": "public", "parameters": [ { - "$id": "514", + "$id": "543", "kind": "query", "name": "def", "serializedName": "def", "type": { - "$id": "515", + "$id": "544", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -7806,12 +8196,12 @@ }, "parameters": [ { - "$id": "516", + "$id": "545", "kind": "method", "name": "def", "serializedName": "def", "type": { - "$id": "517", + "$id": "546", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -7834,24 +8224,24 @@ "crossLanguageDefinitionId": "SpecialWords.Parameters.withDef" }, { - "$id": "518", + "$id": "547", "kind": "basic", "name": "withDel", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "519", + "$id": "548", "name": "withDel", "resourceName": "Parameters", "accessibility": "public", "parameters": [ { - "$id": "520", + "$id": "549", "kind": "query", "name": "del", "serializedName": "del", "type": { - "$id": "521", + "$id": "550", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -7886,12 +8276,12 @@ }, "parameters": [ { - "$id": "522", + "$id": "551", "kind": "method", "name": "del", "serializedName": "del", "type": { - "$id": "523", + "$id": "552", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -7914,24 +8304,24 @@ "crossLanguageDefinitionId": "SpecialWords.Parameters.withDel" }, { - "$id": "524", + "$id": "553", "kind": "basic", "name": "withElif", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "525", + "$id": "554", "name": "withElif", "resourceName": "Parameters", "accessibility": "public", "parameters": [ { - "$id": "526", + "$id": "555", "kind": "query", "name": "elif", "serializedName": "elif", "type": { - "$id": "527", + "$id": "556", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -7966,12 +8356,12 @@ }, "parameters": [ { - "$id": "528", + "$id": "557", "kind": "method", "name": "elif", "serializedName": "elif", "type": { - "$id": "529", + "$id": "558", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -7994,24 +8384,24 @@ "crossLanguageDefinitionId": "SpecialWords.Parameters.withElif" }, { - "$id": "530", + "$id": "559", "kind": "basic", "name": "withElse", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "531", + "$id": "560", "name": "withElse", "resourceName": "Parameters", "accessibility": "public", "parameters": [ { - "$id": "532", + "$id": "561", "kind": "query", "name": "else", "serializedName": "else", "type": { - "$id": "533", + "$id": "562", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -8046,12 +8436,12 @@ }, "parameters": [ { - "$id": "534", + "$id": "563", "kind": "method", "name": "else", "serializedName": "else", "type": { - "$id": "535", + "$id": "564", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -8074,24 +8464,24 @@ "crossLanguageDefinitionId": "SpecialWords.Parameters.withElse" }, { - "$id": "536", + "$id": "565", "kind": "basic", "name": "withExcept", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "537", + "$id": "566", "name": "withExcept", "resourceName": "Parameters", "accessibility": "public", "parameters": [ { - "$id": "538", + "$id": "567", "kind": "query", "name": "except", "serializedName": "except", "type": { - "$id": "539", + "$id": "568", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -8126,12 +8516,12 @@ }, "parameters": [ { - "$id": "540", + "$id": "569", "kind": "method", "name": "except", "serializedName": "except", "type": { - "$id": "541", + "$id": "570", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -8154,24 +8544,24 @@ "crossLanguageDefinitionId": "SpecialWords.Parameters.withExcept" }, { - "$id": "542", + "$id": "571", "kind": "basic", "name": "withExec", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "543", + "$id": "572", "name": "withExec", "resourceName": "Parameters", "accessibility": "public", "parameters": [ { - "$id": "544", + "$id": "573", "kind": "query", "name": "exec", "serializedName": "exec", "type": { - "$id": "545", + "$id": "574", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -8206,12 +8596,12 @@ }, "parameters": [ { - "$id": "546", + "$id": "575", "kind": "method", "name": "exec", "serializedName": "exec", "type": { - "$id": "547", + "$id": "576", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -8234,24 +8624,24 @@ "crossLanguageDefinitionId": "SpecialWords.Parameters.withExec" }, { - "$id": "548", + "$id": "577", "kind": "basic", "name": "withFinally", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "549", + "$id": "578", "name": "withFinally", "resourceName": "Parameters", "accessibility": "public", "parameters": [ { - "$id": "550", + "$id": "579", "kind": "query", "name": "finally", "serializedName": "finally", "type": { - "$id": "551", + "$id": "580", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -8286,12 +8676,12 @@ }, "parameters": [ { - "$id": "552", + "$id": "581", "kind": "method", "name": "finally", "serializedName": "finally", "type": { - "$id": "553", + "$id": "582", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -8314,24 +8704,24 @@ "crossLanguageDefinitionId": "SpecialWords.Parameters.withFinally" }, { - "$id": "554", + "$id": "583", "kind": "basic", "name": "withFor", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "555", + "$id": "584", "name": "withFor", "resourceName": "Parameters", "accessibility": "public", "parameters": [ { - "$id": "556", + "$id": "585", "kind": "query", "name": "for", "serializedName": "for", "type": { - "$id": "557", + "$id": "586", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -8366,12 +8756,12 @@ }, "parameters": [ { - "$id": "558", + "$id": "587", "kind": "method", "name": "for", "serializedName": "for", "type": { - "$id": "559", + "$id": "588", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -8394,24 +8784,24 @@ "crossLanguageDefinitionId": "SpecialWords.Parameters.withFor" }, { - "$id": "560", + "$id": "589", "kind": "basic", "name": "withFrom", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "561", + "$id": "590", "name": "withFrom", "resourceName": "Parameters", "accessibility": "public", "parameters": [ { - "$id": "562", + "$id": "591", "kind": "query", "name": "from", "serializedName": "from", "type": { - "$id": "563", + "$id": "592", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -8446,12 +8836,12 @@ }, "parameters": [ { - "$id": "564", + "$id": "593", "kind": "method", "name": "from", "serializedName": "from", "type": { - "$id": "565", + "$id": "594", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -8474,24 +8864,24 @@ "crossLanguageDefinitionId": "SpecialWords.Parameters.withFrom" }, { - "$id": "566", + "$id": "595", "kind": "basic", "name": "withGlobal", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "567", + "$id": "596", "name": "withGlobal", "resourceName": "Parameters", "accessibility": "public", "parameters": [ { - "$id": "568", + "$id": "597", "kind": "query", "name": "global", "serializedName": "global", "type": { - "$id": "569", + "$id": "598", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -8526,12 +8916,12 @@ }, "parameters": [ { - "$id": "570", + "$id": "599", "kind": "method", "name": "global", "serializedName": "global", "type": { - "$id": "571", + "$id": "600", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -8554,24 +8944,24 @@ "crossLanguageDefinitionId": "SpecialWords.Parameters.withGlobal" }, { - "$id": "572", + "$id": "601", "kind": "basic", "name": "withIf", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "573", + "$id": "602", "name": "withIf", "resourceName": "Parameters", "accessibility": "public", "parameters": [ { - "$id": "574", + "$id": "603", "kind": "query", "name": "if", "serializedName": "if", "type": { - "$id": "575", + "$id": "604", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -8606,12 +8996,12 @@ }, "parameters": [ { - "$id": "576", + "$id": "605", "kind": "method", "name": "if", "serializedName": "if", "type": { - "$id": "577", + "$id": "606", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -8634,24 +9024,24 @@ "crossLanguageDefinitionId": "SpecialWords.Parameters.withIf" }, { - "$id": "578", + "$id": "607", "kind": "basic", "name": "withImport", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "579", + "$id": "608", "name": "withImport", "resourceName": "Parameters", "accessibility": "public", "parameters": [ { - "$id": "580", + "$id": "609", "kind": "query", "name": "import", "serializedName": "import", "type": { - "$id": "581", + "$id": "610", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -8686,12 +9076,12 @@ }, "parameters": [ { - "$id": "582", + "$id": "611", "kind": "method", "name": "import", "serializedName": "import", "type": { - "$id": "583", + "$id": "612", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -8714,24 +9104,24 @@ "crossLanguageDefinitionId": "SpecialWords.Parameters.withImport" }, { - "$id": "584", + "$id": "613", "kind": "basic", "name": "withIn", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "585", + "$id": "614", "name": "withIn", "resourceName": "Parameters", "accessibility": "public", "parameters": [ { - "$id": "586", + "$id": "615", "kind": "query", "name": "in", "serializedName": "in", "type": { - "$id": "587", + "$id": "616", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -8766,12 +9156,12 @@ }, "parameters": [ { - "$id": "588", + "$id": "617", "kind": "method", "name": "in", "serializedName": "in", "type": { - "$id": "589", + "$id": "618", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -8794,24 +9184,24 @@ "crossLanguageDefinitionId": "SpecialWords.Parameters.withIn" }, { - "$id": "590", + "$id": "619", "kind": "basic", "name": "withIs", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "591", + "$id": "620", "name": "withIs", "resourceName": "Parameters", "accessibility": "public", "parameters": [ { - "$id": "592", + "$id": "621", "kind": "query", "name": "is", "serializedName": "is", "type": { - "$id": "593", + "$id": "622", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -8846,12 +9236,12 @@ }, "parameters": [ { - "$id": "594", + "$id": "623", "kind": "method", "name": "is", "serializedName": "is", "type": { - "$id": "595", + "$id": "624", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -8874,24 +9264,24 @@ "crossLanguageDefinitionId": "SpecialWords.Parameters.withIs" }, { - "$id": "596", + "$id": "625", "kind": "basic", "name": "withLambda", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "597", + "$id": "626", "name": "withLambda", "resourceName": "Parameters", "accessibility": "public", "parameters": [ { - "$id": "598", + "$id": "627", "kind": "query", "name": "lambda", "serializedName": "lambda", "type": { - "$id": "599", + "$id": "628", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -8926,12 +9316,12 @@ }, "parameters": [ { - "$id": "600", + "$id": "629", "kind": "method", "name": "lambda", "serializedName": "lambda", "type": { - "$id": "601", + "$id": "630", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -8954,24 +9344,24 @@ "crossLanguageDefinitionId": "SpecialWords.Parameters.withLambda" }, { - "$id": "602", + "$id": "631", "kind": "basic", "name": "withNot", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "603", + "$id": "632", "name": "withNot", "resourceName": "Parameters", "accessibility": "public", "parameters": [ { - "$id": "604", + "$id": "633", "kind": "query", "name": "not", "serializedName": "not", "type": { - "$id": "605", + "$id": "634", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -9006,12 +9396,12 @@ }, "parameters": [ { - "$id": "606", + "$id": "635", "kind": "method", "name": "not", "serializedName": "not", "type": { - "$id": "607", + "$id": "636", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -9034,24 +9424,24 @@ "crossLanguageDefinitionId": "SpecialWords.Parameters.withNot" }, { - "$id": "608", + "$id": "637", "kind": "basic", "name": "withOr", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "609", + "$id": "638", "name": "withOr", "resourceName": "Parameters", "accessibility": "public", "parameters": [ { - "$id": "610", + "$id": "639", "kind": "query", "name": "or", "serializedName": "or", "type": { - "$id": "611", + "$id": "640", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -9086,12 +9476,12 @@ }, "parameters": [ { - "$id": "612", + "$id": "641", "kind": "method", "name": "or", "serializedName": "or", "type": { - "$id": "613", + "$id": "642", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -9114,24 +9504,24 @@ "crossLanguageDefinitionId": "SpecialWords.Parameters.withOr" }, { - "$id": "614", + "$id": "643", "kind": "basic", "name": "withPass", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "615", + "$id": "644", "name": "withPass", "resourceName": "Parameters", "accessibility": "public", "parameters": [ { - "$id": "616", + "$id": "645", "kind": "query", "name": "pass", "serializedName": "pass", "type": { - "$id": "617", + "$id": "646", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -9166,12 +9556,12 @@ }, "parameters": [ { - "$id": "618", + "$id": "647", "kind": "method", "name": "pass", "serializedName": "pass", "type": { - "$id": "619", + "$id": "648", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -9194,24 +9584,24 @@ "crossLanguageDefinitionId": "SpecialWords.Parameters.withPass" }, { - "$id": "620", + "$id": "649", "kind": "basic", "name": "withRaise", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "621", + "$id": "650", "name": "withRaise", "resourceName": "Parameters", "accessibility": "public", "parameters": [ { - "$id": "622", + "$id": "651", "kind": "query", "name": "raise", "serializedName": "raise", "type": { - "$id": "623", + "$id": "652", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -9246,12 +9636,12 @@ }, "parameters": [ { - "$id": "624", + "$id": "653", "kind": "method", "name": "raise", "serializedName": "raise", "type": { - "$id": "625", + "$id": "654", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -9274,24 +9664,24 @@ "crossLanguageDefinitionId": "SpecialWords.Parameters.withRaise" }, { - "$id": "626", + "$id": "655", "kind": "basic", "name": "withReturn", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "627", + "$id": "656", "name": "withReturn", "resourceName": "Parameters", "accessibility": "public", "parameters": [ { - "$id": "628", + "$id": "657", "kind": "query", "name": "return", "serializedName": "return", "type": { - "$id": "629", + "$id": "658", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -9326,12 +9716,12 @@ }, "parameters": [ { - "$id": "630", + "$id": "659", "kind": "method", "name": "return", "serializedName": "return", "type": { - "$id": "631", + "$id": "660", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -9354,24 +9744,24 @@ "crossLanguageDefinitionId": "SpecialWords.Parameters.withReturn" }, { - "$id": "632", + "$id": "661", "kind": "basic", "name": "withTry", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "633", + "$id": "662", "name": "withTry", "resourceName": "Parameters", "accessibility": "public", "parameters": [ { - "$id": "634", + "$id": "663", "kind": "query", "name": "try", "serializedName": "try", "type": { - "$id": "635", + "$id": "664", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -9406,12 +9796,12 @@ }, "parameters": [ { - "$id": "636", + "$id": "665", "kind": "method", "name": "try", "serializedName": "try", "type": { - "$id": "637", + "$id": "666", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -9434,24 +9824,24 @@ "crossLanguageDefinitionId": "SpecialWords.Parameters.withTry" }, { - "$id": "638", + "$id": "667", "kind": "basic", "name": "withWhile", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "639", + "$id": "668", "name": "withWhile", "resourceName": "Parameters", "accessibility": "public", "parameters": [ { - "$id": "640", + "$id": "669", "kind": "query", "name": "while", "serializedName": "while", "type": { - "$id": "641", + "$id": "670", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -9486,12 +9876,12 @@ }, "parameters": [ { - "$id": "642", + "$id": "671", "kind": "method", "name": "while", "serializedName": "while", "type": { - "$id": "643", + "$id": "672", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -9514,24 +9904,24 @@ "crossLanguageDefinitionId": "SpecialWords.Parameters.withWhile" }, { - "$id": "644", + "$id": "673", "kind": "basic", "name": "withWith", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "645", + "$id": "674", "name": "withWith", "resourceName": "Parameters", "accessibility": "public", "parameters": [ { - "$id": "646", + "$id": "675", "kind": "query", "name": "with", "serializedName": "with", "type": { - "$id": "647", + "$id": "676", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -9566,12 +9956,12 @@ }, "parameters": [ { - "$id": "648", + "$id": "677", "kind": "method", "name": "with", "serializedName": "with", "type": { - "$id": "649", + "$id": "678", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -9594,24 +9984,24 @@ "crossLanguageDefinitionId": "SpecialWords.Parameters.withWith" }, { - "$id": "650", + "$id": "679", "kind": "basic", "name": "withYield", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "651", + "$id": "680", "name": "withYield", "resourceName": "Parameters", "accessibility": "public", "parameters": [ { - "$id": "652", + "$id": "681", "kind": "query", "name": "yield", "serializedName": "yield", "type": { - "$id": "653", + "$id": "682", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -9646,12 +10036,12 @@ }, "parameters": [ { - "$id": "654", + "$id": "683", "kind": "method", "name": "yield", "serializedName": "yield", "type": { - "$id": "655", + "$id": "684", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -9674,24 +10064,24 @@ "crossLanguageDefinitionId": "SpecialWords.Parameters.withYield" }, { - "$id": "656", + "$id": "685", "kind": "basic", "name": "withCancellationToken", "accessibility": "public", "apiVersions": [], "operation": { - "$id": "657", + "$id": "686", "name": "withCancellationToken", "resourceName": "Parameters", "accessibility": "public", "parameters": [ { - "$id": "658", + "$id": "687", "kind": "query", "name": "cancellationToken", "serializedName": "cancellationToken", "type": { - "$id": "659", + "$id": "688", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -9726,12 +10116,12 @@ }, "parameters": [ { - "$id": "660", + "$id": "689", "kind": "method", "name": "cancellationToken", "serializedName": "cancellationToken", "type": { - "$id": "661", + "$id": "690", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -9756,13 +10146,13 @@ ], "parameters": [ { - "$id": "662", + "$id": "691", "kind": "endpoint", "name": "endpoint", "serializedName": "endpoint", "doc": "Service host", "type": { - "$id": "663", + "$id": "692", "kind": "url", "name": "endpoint", "crossLanguageDefinitionId": "TypeSpec.url" @@ -9773,7 +10163,7 @@ "isEndpoint": true, "defaultValue": { "type": { - "$id": "664", + "$id": "693", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string" @@ -9791,7 +10181,7 @@ "crossLanguageDefinitionId": "SpecialWords.Parameters", "apiVersions": [], "parent": { - "$ref": "171" + "$ref": "194" } } ] diff --git a/packages/http-client-csharp/package-lock.json b/packages/http-client-csharp/package-lock.json index 7dc6de2be4b..41998dd9816 100644 --- a/packages/http-client-csharp/package-lock.json +++ b/packages/http-client-csharp/package-lock.json @@ -9,22 +9,22 @@ "version": "1.0.0", "license": "MIT", "devDependencies": { - "@azure-tools/azure-http-specs": "0.1.0-alpha.32", - "@azure-tools/typespec-client-generator-core": "0.62.0", + "@azure-tools/azure-http-specs": "0.1.0-alpha.33", + "@azure-tools/typespec-client-generator-core": "0.63.0", "@microsoft/api-extractor": "^7.52.2", "@types/node": "~22.12.0", - "@typespec/compiler": "1.6.0", - "@typespec/http": "1.6.0", - "@typespec/http-specs": "0.1.0-alpha.28", - "@typespec/json-schema": "1.6.0", - "@typespec/library-linter": "0.76.0", - "@typespec/openapi": "1.6.0", - "@typespec/rest": "0.76.0", + "@typespec/compiler": "1.7.0", + "@typespec/http": "1.7.0", + "@typespec/http-specs": "0.1.0-alpha.29", + "@typespec/json-schema": "1.7.0", + "@typespec/library-linter": "0.77.0", + "@typespec/openapi": "1.7.0", + "@typespec/rest": "0.77.0", "@typespec/spector": "0.1.0-alpha.20", - "@typespec/streams": "0.76.0", + "@typespec/streams": "0.77.0", "@typespec/tspd": "0.73.1", - "@typespec/versioning": "0.76.0", - "@typespec/xml": "0.76.0", + "@typespec/versioning": "0.77.0", + "@typespec/xml": "0.77.0", "@vitest/coverage-v8": "^3.0.5", "@vitest/ui": "^3.0.5", "c8": "^10.1.2", @@ -33,13 +33,13 @@ "vitest": "^3.0.5" }, "peerDependencies": { - "@azure-tools/typespec-client-generator-core": ">=0.62.0 < 0.63.0 || ~0.63.0-0", - "@typespec/compiler": "^1.6.0", - "@typespec/http": "^1.6.0", - "@typespec/openapi": "^1.6.0", - "@typespec/rest": ">=0.76.0 <0.77.0 || ~0.77.0-0", - "@typespec/streams": ">=0.76.0 <0.77.0 || ~0.77.0-0", - "@typespec/versioning": ">=0.76.0 <0.77.0 || ~0.77.0-0" + "@azure-tools/typespec-client-generator-core": ">=0.63.0 < 0.64.0 || ~0.64.0-0", + "@typespec/compiler": "^1.7.0", + "@typespec/http": "^1.7.0", + "@typespec/openapi": "^1.7.0", + "@typespec/rest": ">=0.77.0 <0.78.0 || ~0.78.0-0", + "@typespec/streams": ">=0.77.0 <0.78.0 || ~0.78.0-0", + "@typespec/versioning": ">=0.77.0 <0.78.0 || ~0.78.0-0" } }, "node_modules/@alloy-js/core": { @@ -94,31 +94,185 @@ } }, "node_modules/@azure-tools/azure-http-specs": { - "version": "0.1.0-alpha.32", - "resolved": "https://registry.npmjs.org/@azure-tools/azure-http-specs/-/azure-http-specs-0.1.0-alpha.32.tgz", - "integrity": "sha512-TjPu0vZyGdAXHw1HHuExNdR2/m4JJZamrHl2TWsCOMGo1loxWVb/mTitVbi0SUkYqzKfCiKrQ+pMcHNxUvJ35Q==", + "version": "0.1.0-alpha.33", + "resolved": "https://registry.npmjs.org/@azure-tools/azure-http-specs/-/azure-http-specs-0.1.0-alpha.33.tgz", + "integrity": "sha512-AjwAF9czpgqToa5sqYZhMLSRoM9+i4O9mPxOGFqbSuGd5pfkg9TKKpGCapTT5cXnvsAx7O8fW8XxiLGMmVPF2g==", "dev": true, "license": "MIT", "dependencies": { - "@typespec/spec-api": "^0.1.0-alpha.10", - "@typespec/spector": "^0.1.0-alpha.20" + "@typespec/spec-api": "^0.1.0-alpha.11", + "@typespec/spector": "^0.1.0-alpha.21" }, "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@azure-tools/typespec-azure-core": "^0.62.0", - "@typespec/compiler": "^1.6.0", - "@typespec/http": "^1.6.0", - "@typespec/rest": "^0.76.0", - "@typespec/versioning": "^0.76.0", - "@typespec/xml": "^0.76.0" + "@azure-tools/typespec-azure-core": "^0.63.0", + "@typespec/compiler": "^1.7.0", + "@typespec/http": "^1.7.0", + "@typespec/rest": "^0.77.0", + "@typespec/versioning": "^0.77.0", + "@typespec/xml": "^0.77.0" + } + }, + "node_modules/@azure-tools/azure-http-specs/node_modules/@typespec/spector": { + "version": "0.1.0-alpha.21", + "resolved": "https://registry.npmjs.org/@typespec/spector/-/spector-0.1.0-alpha.21.tgz", + "integrity": "sha512-oLtAs2/E+ee/OPeMZnRUxiuVjUeYaxi5R1KeFThAjLszp6M2rkCfeIdyj2RosGxiqWrmoEd9oCWO/fHwvGVZew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/identity": "~4.13.0", + "@typespec/compiler": "^1.7.0", + "@typespec/http": "^1.7.0", + "@typespec/rest": "^0.77.0", + "@typespec/spec-api": "^0.1.0-alpha.11", + "@typespec/spec-coverage-sdk": "^0.1.0-alpha.13", + "@typespec/versioning": "^0.77.0", + "ajv": "~8.17.1", + "body-parser": "^2.2.0", + "deep-equal": "^2.2.0", + "express": "^5.1.0", + "globby": "~16.0.0", + "micromatch": "^4.0.8", + "morgan": "^1.10.0", + "multer": "^2.0.1", + "picocolors": "~1.1.1", + "source-map-support": "~0.5.21", + "xml2js": "^0.6.2", + "yaml": "~2.8.0", + "yargs": "~18.0.0" + }, + "bin": { + "tsp-spector": "cmd/cli.mjs" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@azure-tools/azure-http-specs/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@azure-tools/azure-http-specs/node_modules/cliui": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@azure-tools/azure-http-specs/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@azure-tools/azure-http-specs/node_modules/globby": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-16.0.0.tgz", + "integrity": "sha512-ejy4TJFga99yW6Q0uhM3pFawKWZmtZzZD/v/GwI5+9bCV5Ew+D2pSND6W7fUes5UykqSsJkUfxFVdRh7Q1+P3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^4.0.0", + "fast-glob": "^3.3.3", + "ignore": "^7.0.5", + "is-path-inside": "^4.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.4.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@azure-tools/azure-http-specs/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@azure-tools/azure-http-specs/node_modules/unicorn-magic": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.4.0.tgz", + "integrity": "sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@azure-tools/azure-http-specs/node_modules/yargs": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", + "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^9.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "string-width": "^7.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^22.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/@azure-tools/azure-http-specs/node_modules/yargs-parser": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" } }, "node_modules/@azure-tools/typespec-azure-core": { - "version": "0.62.0", - "resolved": "https://registry.npmjs.org/@azure-tools/typespec-azure-core/-/typespec-azure-core-0.62.0.tgz", - "integrity": "sha512-4LIFqNHhKO1/jiCH0U2rfI+yH7vkWcFuwpjNyRTWXw/YghAI2d+aIEwtT4oM8jWeYR3KUQfA6AqGPRCm90AXYA==", + "version": "0.63.0", + "resolved": "https://registry.npmjs.org/@azure-tools/typespec-azure-core/-/typespec-azure-core-0.63.0.tgz", + "integrity": "sha512-FbEmpZSQENzBt/Y8qSF1b98T8CqT3bV7IRV8AGGm/73NQZiWQCm2LvQzR0/lbqGntS2EnSBrt394Kt69wM4ifA==", "dev": true, "license": "MIT", "peer": true, @@ -126,15 +280,15 @@ "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.6.0", - "@typespec/http": "^1.6.0", - "@typespec/rest": "^0.76.0" + "@typespec/compiler": "^1.7.0", + "@typespec/http": "^1.7.0", + "@typespec/rest": "^0.77.0" } }, "node_modules/@azure-tools/typespec-client-generator-core": { - "version": "0.62.0", - "resolved": "https://registry.npmjs.org/@azure-tools/typespec-client-generator-core/-/typespec-client-generator-core-0.62.0.tgz", - "integrity": "sha512-fZilNfvqIW6Jzb97SuM5f+i9p5b0261InQRbQcTbeuYGtb5z5M0v8tuGglE4adU8NqQ1OmEv/oRjQjSeSjlxwA==", + "version": "0.63.0", + "resolved": "https://registry.npmjs.org/@azure-tools/typespec-client-generator-core/-/typespec-client-generator-core-0.63.0.tgz", + "integrity": "sha512-zpvFvjCjNW+GWzHBV7vJ2E1PKXrmyNqp7FQiYo/D7PJBVTXNtOyIKqqo043ktAaWihbr8cl5QguuNSoBAKL0+Q==", "dev": true, "license": "MIT", "dependencies": { @@ -146,16 +300,16 @@ "node": ">=20.0.0" }, "peerDependencies": { - "@azure-tools/typespec-azure-core": "^0.62.0", - "@typespec/compiler": "^1.6.0", - "@typespec/events": "^0.76.0", - "@typespec/http": "^1.6.0", - "@typespec/openapi": "^1.6.0", - "@typespec/rest": "^0.76.0", - "@typespec/sse": "^0.76.0", - "@typespec/streams": "^0.76.0", - "@typespec/versioning": "^0.76.0", - "@typespec/xml": "^0.76.0" + "@azure-tools/typespec-azure-core": "^0.63.0", + "@typespec/compiler": "^1.7.0", + "@typespec/events": "^0.77.0", + "@typespec/http": "^1.7.0", + "@typespec/openapi": "^1.7.0", + "@typespec/rest": "^0.77.0", + "@typespec/sse": "^0.77.0", + "@typespec/streams": "^0.77.0", + "@typespec/versioning": "^0.77.0", + "@typespec/xml": "^0.77.0" } }, "node_modules/@azure/abort-controller": { @@ -974,21 +1128,30 @@ "@shikijs/vscode-textmate": "^10.0.2" } }, + "node_modules/@inquirer/ansi": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-2.0.2.tgz", + "integrity": "sha512-SYLX05PwJVnW+WVegZt1T4Ip1qba1ik+pNJPDiqvk6zS5Y/i8PhRzLpGEtVd7sW0G8cMtkD8t4AZYhQwm8vnww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + } + }, "node_modules/@inquirer/checkbox": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.2.0.tgz", - "integrity": "sha512-fdSw07FLJEU5vbpOPzXo5c6xmMGDzbZE2+niuDHX5N6mc6V0Ebso/q3xiHra4D73+PMsC8MJmcaZKuAAoaQsSA==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-5.0.2.tgz", + "integrity": "sha512-iTPV4tMMct7iOpwer5qmTP7gjnk1VQJjsNfAaC2b8Q3qiuHM3K2yjjDr5u1MKfkrvp2JD4Flf8sIPpF21pmZmw==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.15", - "@inquirer/figures": "^1.0.13", - "@inquirer/type": "^3.0.8", - "ansi-escapes": "^4.3.2", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/ansi": "^2.0.2", + "@inquirer/core": "^11.0.2", + "@inquirer/figures": "^2.0.2", + "@inquirer/type": "^4.0.2" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -1000,17 +1163,17 @@ } }, "node_modules/@inquirer/confirm": { - "version": "5.1.14", - "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.14.tgz", - "integrity": "sha512-5yR4IBfe0kXe59r1YCTG8WXkUbl7Z35HK87Sw+WUyGD8wNUx7JvY7laahzeytyE1oLn74bQnL7hstctQxisQ8Q==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-6.0.2.tgz", + "integrity": "sha512-A0/13Wyi+8iFeNDX6D4zZYKPoBLIEbE4K/219qHcnpXMer2weWvaTo63+2c7mQPPA206DEMSYVOPnEw3meOlCw==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.15", - "@inquirer/type": "^3.0.8" + "@inquirer/core": "^11.0.2", + "@inquirer/type": "^4.0.2" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -1022,23 +1185,22 @@ } }, "node_modules/@inquirer/core": { - "version": "10.1.15", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.1.15.tgz", - "integrity": "sha512-8xrp836RZvKkpNbVvgWUlxjT4CraKk2q+I3Ksy+seI2zkcE+y6wNs1BVhgcv8VyImFecUhdQrYLdW32pAjwBdA==", + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-11.0.2.tgz", + "integrity": "sha512-lgMRx/n02ciiNELBvFLHtmcjbV5tf5D/I0UYfCg2YbTZWmBZ10/niLd3IjWBxz8LtM27xP+4oLEa06Slmb7p7A==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/figures": "^1.0.13", - "@inquirer/type": "^3.0.8", - "ansi-escapes": "^4.3.2", + "@inquirer/ansi": "^2.0.2", + "@inquirer/figures": "^2.0.2", + "@inquirer/type": "^4.0.2", "cli-width": "^4.1.0", - "mute-stream": "^2.0.0", + "mute-stream": "^3.0.0", "signal-exit": "^4.1.0", - "wrap-ansi": "^6.2.0", - "yoctocolors-cjs": "^2.1.2" + "wrap-ansi": "^9.0.2" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -1050,18 +1212,18 @@ } }, "node_modules/@inquirer/editor": { - "version": "4.2.15", - "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.15.tgz", - "integrity": "sha512-wst31XT8DnGOSS4nNJDIklGKnf+8shuauVrWzgKegWUe28zfCftcWZ2vktGdzJgcylWSS2SrDnYUb6alZcwnCQ==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-5.0.2.tgz", + "integrity": "sha512-pXQ4Nf0qmFcJuYB6NlcIIxH6l6zKOwNg1Jh/ZRdKd2dTqBB4OXKUFbFwR2K4LVXVtq15ZFFatBVT+rerYR8hWQ==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.15", - "@inquirer/type": "^3.0.8", - "external-editor": "^3.1.0" + "@inquirer/core": "^11.0.2", + "@inquirer/external-editor": "^2.0.2", + "@inquirer/type": "^4.0.2" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -1073,18 +1235,39 @@ } }, "node_modules/@inquirer/expand": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.17.tgz", - "integrity": "sha512-PSqy9VmJx/VbE3CT453yOfNa+PykpKg/0SYP7odez1/NWBGuDXgPhp4AeGYYKjhLn5lUUavVS/JbeYMPdH50Mw==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-5.0.2.tgz", + "integrity": "sha512-siFG1swxfjFIOxIcehtZkh+KUNB/YCpyfHNEGu+nC/SBXIbgUWibvThLn/WesSxLRGOeSKdNKoTm+GQCKFm6Ww==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.15", - "@inquirer/type": "^3.0.8", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/core": "^11.0.2", + "@inquirer/type": "^4.0.2" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/external-editor": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-2.0.2.tgz", + "integrity": "sha512-X/fMXK7vXomRWEex1j8mnj7s1mpnTeP4CO/h2gysJhHLT2WjBnLv4ZQEGpm/kcYI8QfLZ2fgW+9kTKD+jeopLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chardet": "^2.1.1", + "iconv-lite": "^0.7.0" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -1095,28 +1278,45 @@ } } }, + "node_modules/@inquirer/external-editor/node_modules/iconv-lite": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", + "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/@inquirer/figures": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.13.tgz", - "integrity": "sha512-lGPVU3yO9ZNqA7vTYz26jny41lE7yoQansmqdMLBEfqaGsmdg7V3W9mK9Pvb5IL4EVZ9GnSDGMO/cJXud5dMaw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-2.0.2.tgz", + "integrity": "sha512-qXm6EVvQx/FmnSrCWCIGtMHwqeLgxABP8XgcaAoywsL0NFga9gD5kfG0gXiv80GjK9Hsoz4pgGwF/+CjygyV9A==", "dev": true, "license": "MIT", "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" } }, "node_modules/@inquirer/input": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.2.1.tgz", - "integrity": "sha512-tVC+O1rBl0lJpoUZv4xY+WGWY8V5b0zxU1XDsMsIHYregdh7bN5X5QnIONNBAl0K765FYlAfNHS2Bhn7SSOVow==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-5.0.2.tgz", + "integrity": "sha512-hN2YRo1QiEc9lD3mK+CPnTS4TK2RhCMmMmP4nCWwTkmQL2vx9jPJWYk+rbUZpwR1D583ZJk1FI3i9JZXIpi/qg==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.15", - "@inquirer/type": "^3.0.8" + "@inquirer/core": "^11.0.2", + "@inquirer/type": "^4.0.2" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -1128,17 +1328,17 @@ } }, "node_modules/@inquirer/number": { - "version": "3.0.17", - "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.17.tgz", - "integrity": "sha512-GcvGHkyIgfZgVnnimURdOueMk0CztycfC8NZTiIY9arIAkeOgt6zG57G+7vC59Jns3UX27LMkPKnKWAOF5xEYg==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-4.0.2.tgz", + "integrity": "sha512-4McnjTSYrlthNW1ojkkmP75WLRYhQs7GXm6pDDoIrHqJuV5uUYwfdbB0geHdaKMarAqJQgoOVjzIT0jdWCsKew==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.15", - "@inquirer/type": "^3.0.8" + "@inquirer/core": "^11.0.2", + "@inquirer/type": "^4.0.2" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -1150,18 +1350,18 @@ } }, "node_modules/@inquirer/password": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.17.tgz", - "integrity": "sha512-DJolTnNeZ00E1+1TW+8614F7rOJJCM4y4BAGQ3Gq6kQIG+OJ4zr3GLjIjVVJCbKsk2jmkmv6v2kQuN/vriHdZA==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-5.0.2.tgz", + "integrity": "sha512-oSDziMKiw4G2e4zS+0JRfxuPFFGh6N/9yUaluMgEHp2/Yyj2JGwfDO7XbwtOrxVrz+XsP/iaGyWXdQb9d8A0+g==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.15", - "@inquirer/type": "^3.0.8", - "ansi-escapes": "^4.3.2" + "@inquirer/ansi": "^2.0.2", + "@inquirer/core": "^11.0.2", + "@inquirer/type": "^4.0.2" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -1173,25 +1373,25 @@ } }, "node_modules/@inquirer/prompts": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.7.1.tgz", - "integrity": "sha512-XDxPrEWeWUBy8scAXzXuFY45r/q49R0g72bUzgQXZ1DY/xEFX+ESDMkTQolcb5jRBzaNJX2W8XQl6krMNDTjaA==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-8.0.2.tgz", + "integrity": "sha512-2zK5zY48fZcl6+gG4eqOC/UzZsJckHCRvjXoLuW4D8LKOCVGdcJiSKkLnumSZjR/6PXPINDGOrGHqNxb+sxJDg==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/checkbox": "^4.2.0", - "@inquirer/confirm": "^5.1.14", - "@inquirer/editor": "^4.2.15", - "@inquirer/expand": "^4.0.17", - "@inquirer/input": "^4.2.1", - "@inquirer/number": "^3.0.17", - "@inquirer/password": "^4.0.17", - "@inquirer/rawlist": "^4.1.5", - "@inquirer/search": "^3.0.17", - "@inquirer/select": "^4.3.1" + "@inquirer/checkbox": "^5.0.2", + "@inquirer/confirm": "^6.0.2", + "@inquirer/editor": "^5.0.2", + "@inquirer/expand": "^5.0.2", + "@inquirer/input": "^5.0.2", + "@inquirer/number": "^4.0.2", + "@inquirer/password": "^5.0.2", + "@inquirer/rawlist": "^5.0.2", + "@inquirer/search": "^4.0.2", + "@inquirer/select": "^5.0.2" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -1203,18 +1403,17 @@ } }, "node_modules/@inquirer/rawlist": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.5.tgz", - "integrity": "sha512-R5qMyGJqtDdi4Ht521iAkNqyB6p2UPuZUbMifakg1sWtu24gc2Z8CJuw8rP081OckNDMgtDCuLe42Q2Kr3BolA==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-5.0.2.tgz", + "integrity": "sha512-AcNALEdQKUQDeJcpC1a3YC53m1MLv+sMUS+vRZ8Qigs1Yg3Dcdtmi82rscJplogKOY8CXkKW4wvVwHS2ZjCIBQ==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.15", - "@inquirer/type": "^3.0.8", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/core": "^11.0.2", + "@inquirer/type": "^4.0.2" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -1226,19 +1425,18 @@ } }, "node_modules/@inquirer/search": { - "version": "3.0.17", - "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.0.17.tgz", - "integrity": "sha512-CuBU4BAGFqRYors4TNCYzy9X3DpKtgIW4Boi0WNkm4Ei1hvY9acxKdBdyqzqBCEe4YxSdaQQsasJlFlUJNgojw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-4.0.2.tgz", + "integrity": "sha512-hg63w5toohdzE65S3LiGhdfIL0kT+yisbZARf7zw65PvyMUTutTN3eMAvD/B6y/25z88vTrB7kSB45Vz5CbrXg==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.15", - "@inquirer/figures": "^1.0.13", - "@inquirer/type": "^3.0.8", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/core": "^11.0.2", + "@inquirer/figures": "^2.0.2", + "@inquirer/type": "^4.0.2" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -1250,20 +1448,19 @@ } }, "node_modules/@inquirer/select": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.3.1.tgz", - "integrity": "sha512-Gfl/5sqOF5vS/LIrSndFgOh7jgoe0UXEizDqahFRkq5aJBLegZ6WjuMh/hVEJwlFQjyLq1z9fRtvUMkb7jM1LA==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-5.0.2.tgz", + "integrity": "sha512-JygTohvQxSNnvt7IKANVlg/eds+yN5sLRilYeGc4ri/9Aqi/2QPoXBMV5Cz/L1VtQv63SnTbPXJZeCK2pSwsOA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.15", - "@inquirer/figures": "^1.0.13", - "@inquirer/type": "^3.0.8", - "ansi-escapes": "^4.3.2", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/ansi": "^2.0.2", + "@inquirer/core": "^11.0.2", + "@inquirer/figures": "^2.0.2", + "@inquirer/type": "^4.0.2" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -1275,13 +1472,13 @@ } }, "node_modules/@inquirer/type": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.8.tgz", - "integrity": "sha512-lg9Whz8onIHRthWaN1Q9EGLa/0LFJjyM8mEUbL1eTi6yMGvBf8gvyDLtxSXztQsxMvhxxNpJYrwa1YHdq+w4Jw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.0.2.tgz", + "integrity": "sha512-cae7mzluplsjSdgFA6ACLygb5jC8alO0UUnFPyu0E7tNRPrL+q/f8VcSXp+cjZQ7l5CMpDpi2G1+IQvkOiL1Lw==", "dev": true, "license": "MIT", "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -2066,7 +2263,6 @@ "integrity": "sha512-Fll2FZ1riMjNmlmJOdAyY5pUbkftXslB5DgEzlIuNaiWhXd00FhWxVC/r4yV/4wBb9JfImTu+jiSvXTkJ7F/gA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~6.20.0" } @@ -2079,32 +2275,31 @@ "license": "MIT" }, "node_modules/@typespec/asset-emitter": { - "version": "0.76.0", - "resolved": "https://registry.npmjs.org/@typespec/asset-emitter/-/asset-emitter-0.76.0.tgz", - "integrity": "sha512-+zXpntzHujfoVA7FiE3IIerM79fqo4BvT9E4PaeBybt2L6mNMxgWteE8j1ztNfDDMeOG4fkL2bv3+/ZD+DDP/Q==", + "version": "0.77.0", + "resolved": "https://registry.npmjs.org/@typespec/asset-emitter/-/asset-emitter-0.77.0.tgz", + "integrity": "sha512-OoeYP3UZ/taf46U6sEcb11VYmBlgpCn02mdHTIAM+suCjBZPBYV02pkeEvKyms4MtHMsg/GdEh7Tpl6cTwwsNg==", "dev": true, "license": "MIT", "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.6.0" + "@typespec/compiler": "^1.7.0" } }, "node_modules/@typespec/compiler": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@typespec/compiler/-/compiler-1.6.0.tgz", - "integrity": "sha512-yxyV+ch8tnqiuU2gClv/mQEESoFwpkjo6177UkYfV0nVA9PzTg4zVVc7+WIMZk04wiLRRT3H1uc11FB1cwLY3g==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@typespec/compiler/-/compiler-1.7.0.tgz", + "integrity": "sha512-KE2t5I7u/33M/nsIxdng06FUPrqaGSbMsSEsv51eMwYnj3v1+Z3qTTX/dxHAXRXHcfadNlX/NtyAKju+pkMTFQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "~7.27.1", - "@inquirer/prompts": "^7.4.0", + "@inquirer/prompts": "^8.0.1", "ajv": "~8.17.1", "change-case": "~5.4.4", "env-paths": "^3.0.0", - "globby": "~15.0.0", + "globby": "~16.0.0", "is-unicode-supported": "^2.1.0", "mustache": "~4.2.0", "picocolors": "~1.1.1", @@ -2142,19 +2337,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@typespec/compiler/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/@typespec/compiler/node_modules/cliui": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", @@ -2177,6 +2359,27 @@ "dev": true, "license": "MIT" }, + "node_modules/@typespec/compiler/node_modules/globby": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-16.0.0.tgz", + "integrity": "sha512-ejy4TJFga99yW6Q0uhM3pFawKWZmtZzZD/v/GwI5+9bCV5Ew+D2pSND6W7fUes5UykqSsJkUfxFVdRh7Q1+P3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^4.0.0", + "fast-glob": "^3.3.3", + "ignore": "^7.0.5", + "is-path-inside": "^4.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.4.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@typespec/compiler/node_modules/semver": { "version": "7.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", @@ -2208,22 +2411,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@typespec/compiler/node_modules/wrap-ansi": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", - "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "node_modules/@typespec/compiler/node_modules/unicorn-magic": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.4.0.tgz", + "integrity": "sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==", "dev": true, "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" - }, "engines": { - "node": ">=18" + "node": ">=20" }, "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/@typespec/compiler/node_modules/yargs": { @@ -2255,9 +2453,9 @@ } }, "node_modules/@typespec/events": { - "version": "0.76.0", - "resolved": "https://registry.npmjs.org/@typespec/events/-/events-0.76.0.tgz", - "integrity": "sha512-mdjYQ5HA3Y4ZeyAEmiIDdRa9hbc/5qey5hU9UCA0gL+YWVYgoqLPbZQQTwqq3smM35+5cWp9GTGPyNHcOoRwOA==", + "version": "0.77.0", + "resolved": "https://registry.npmjs.org/@typespec/events/-/events-0.77.0.tgz", + "integrity": "sha512-NbOzi7axEt/xGgXaLjcGGV2HjQKNFjbvsQpCeDA6loUghZDK5+5ik/jwMumeUDunoBsAKF78ZxVF5qhQh56dGA==", "dev": true, "license": "MIT", "peer": true, @@ -2265,22 +2463,21 @@ "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.6.0" + "@typespec/compiler": "^1.7.0" } }, "node_modules/@typespec/http": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@typespec/http/-/http-1.6.0.tgz", - "integrity": "sha512-q/JwVw21CF4buE3ZS+xSoy2TKAOwyhZ7g3kdNqCgm69BI5p5GGu+3ZlUA+4Blk8hkt0G8XcIN8fhJP+a4O6KAw==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@typespec/http/-/http-1.7.0.tgz", + "integrity": "sha512-4cGkcMiob3bedWbFkRcq614TDH7WPEI3YMgrg44mBarj903arpEniAESIhNUbLQzQFFc5rOJagexQDl4agVDyA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.6.0", - "@typespec/streams": "^0.76.0" + "@typespec/compiler": "^1.7.0", + "@typespec/streams": "^0.77.0" }, "peerDependenciesMeta": { "@typespec/streams": { @@ -2288,92 +2485,244 @@ } } }, - "node_modules/@typespec/http-specs": { - "version": "0.1.0-alpha.28", - "resolved": "https://registry.npmjs.org/@typespec/http-specs/-/http-specs-0.1.0-alpha.28.tgz", - "integrity": "sha512-JnJhj/ZkmzZ4g8pnCmyP4oQQt3UbAaTGw/6SAyT8ETG+uPmrS8xgJKaxcSU1Ihaher2WY8MQ6mu7F8V+CV4e5w==", + "node_modules/@typespec/http-specs": { + "version": "0.1.0-alpha.29", + "resolved": "https://registry.npmjs.org/@typespec/http-specs/-/http-specs-0.1.0-alpha.29.tgz", + "integrity": "sha512-SB/NhbTllJzJchcyASixr7i+m6InyY1VjhckKiofVgU9mnoOuZTr8BQG0yrOGzWxZkm93/doDFp7kZdHSbEJQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typespec/spec-api": "^0.1.0-alpha.11", + "@typespec/spector": "^0.1.0-alpha.21", + "deep-equal": "^2.2.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@typespec/compiler": "^1.7.0", + "@typespec/http": "^1.7.0", + "@typespec/rest": "^0.77.0", + "@typespec/versioning": "^0.77.0", + "@typespec/xml": "^0.77.0" + } + }, + "node_modules/@typespec/http-specs/node_modules/@typespec/spector": { + "version": "0.1.0-alpha.21", + "resolved": "https://registry.npmjs.org/@typespec/spector/-/spector-0.1.0-alpha.21.tgz", + "integrity": "sha512-oLtAs2/E+ee/OPeMZnRUxiuVjUeYaxi5R1KeFThAjLszp6M2rkCfeIdyj2RosGxiqWrmoEd9oCWO/fHwvGVZew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/identity": "~4.13.0", + "@typespec/compiler": "^1.7.0", + "@typespec/http": "^1.7.0", + "@typespec/rest": "^0.77.0", + "@typespec/spec-api": "^0.1.0-alpha.11", + "@typespec/spec-coverage-sdk": "^0.1.0-alpha.13", + "@typespec/versioning": "^0.77.0", + "ajv": "~8.17.1", + "body-parser": "^2.2.0", + "deep-equal": "^2.2.0", + "express": "^5.1.0", + "globby": "~16.0.0", + "micromatch": "^4.0.8", + "morgan": "^1.10.0", + "multer": "^2.0.1", + "picocolors": "~1.1.1", + "source-map-support": "~0.5.21", + "xml2js": "^0.6.2", + "yaml": "~2.8.0", + "yargs": "~18.0.0" + }, + "bin": { + "tsp-spector": "cmd/cli.mjs" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@typespec/http-specs/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@typespec/http-specs/node_modules/cliui": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@typespec/http-specs/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typespec/http-specs/node_modules/globby": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-16.0.0.tgz", + "integrity": "sha512-ejy4TJFga99yW6Q0uhM3pFawKWZmtZzZD/v/GwI5+9bCV5Ew+D2pSND6W7fUes5UykqSsJkUfxFVdRh7Q1+P3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^4.0.0", + "fast-glob": "^3.3.3", + "ignore": "^7.0.5", + "is-path-inside": "^4.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.4.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@typespec/http-specs/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@typespec/http-specs/node_modules/unicorn-magic": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.4.0.tgz", + "integrity": "sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@typespec/http-specs/node_modules/yargs": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", + "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^9.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "string-width": "^7.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^22.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/@typespec/http-specs/node_modules/yargs-parser": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", "dev": true, - "license": "MIT", - "dependencies": { - "@typespec/spec-api": "^0.1.0-alpha.10", - "@typespec/spector": "^0.1.0-alpha.20", - "deep-equal": "^2.2.0" - }, + "license": "ISC", "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@typespec/compiler": "^1.6.0", - "@typespec/http": "^1.6.0", - "@typespec/rest": "^0.76.0", - "@typespec/versioning": "^0.76.0", - "@typespec/xml": "^0.76.0" + "node": "^20.19.0 || ^22.12.0 || >=23" } }, "node_modules/@typespec/json-schema": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@typespec/json-schema/-/json-schema-1.6.0.tgz", - "integrity": "sha512-Zf27bo/lfIhN4QhCQI//wnWXf/H+ETN5lE5k3IKIsnMUcS4GW+WlQNGZUEMYXEBd1t4J8VCSXppuuPepIQoh9Q==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@typespec/json-schema/-/json-schema-1.7.0.tgz", + "integrity": "sha512-patXNO5r8ly56LpR/IZtMvEa5w1l7RIOEagWRsmfCd5LxiwTAucEQNZr8tnUBXHAIaQ4MM//8gTrRJ5/HPql1A==", "dev": true, "license": "MIT", "dependencies": { - "@typespec/asset-emitter": "^0.76.0", + "@typespec/asset-emitter": "^0.77.0", "yaml": "~2.8.0" }, "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.6.0" + "@typespec/compiler": "^1.7.0" } }, "node_modules/@typespec/library-linter": { - "version": "0.76.0", - "resolved": "https://registry.npmjs.org/@typespec/library-linter/-/library-linter-0.76.0.tgz", - "integrity": "sha512-pdWQST0vLqIKIYHFt4lYJbLL9cNKrmSDUic50CLX+DW0MefKj3D+Ws/PTSY65TNgfoN1CNgGBeHLPWyv2uWHmw==", + "version": "0.77.0", + "resolved": "https://registry.npmjs.org/@typespec/library-linter/-/library-linter-0.77.0.tgz", + "integrity": "sha512-F9nMAUyc/kEde7tv9+Tx3RZw5AiAIwnidG9Usxl2EMccZuLfYqv+gFu39tNtae9rYqZd58BqFnr60ljTTE0nVA==", "dev": true, "license": "MIT", "engines": { "node": ">=14.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.6.0" + "@typespec/compiler": "^1.7.0" } }, "node_modules/@typespec/openapi": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@typespec/openapi/-/openapi-1.6.0.tgz", - "integrity": "sha512-KuxYAzfP5ljM0PUhSGclNZgTG0H+kyTQcwn6cf4TKhO72R2QMQmiMtN2plqvzsfkL+TLwad1iZhMWTCAMFAQ4w==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@typespec/openapi/-/openapi-1.7.0.tgz", + "integrity": "sha512-tEAIgGnjLvOjbGAoCfkBudvpe/tXaOXkzy5nVFXs4921/jAaMTwzcJIt0bTXZpp5cExdlL7w9ZrnehARHiposQ==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.6.0", - "@typespec/http": "^1.6.0" + "@typespec/compiler": "^1.7.0", + "@typespec/http": "^1.7.0" } }, "node_modules/@typespec/rest": { - "version": "0.76.0", - "resolved": "https://registry.npmjs.org/@typespec/rest/-/rest-0.76.0.tgz", - "integrity": "sha512-6jtQWdcmuKyG9cmqWsJjaq64f6N5B/1DS4X3ZoTNgYhHA27Hnsxo1HZWXcpv7Wl+MxLAZM6kgpML0ugDEZcrYQ==", + "version": "0.77.0", + "resolved": "https://registry.npmjs.org/@typespec/rest/-/rest-0.77.0.tgz", + "integrity": "sha512-DEUMD9zYqUVUhKCGktV7Z+sFkzj+bcSpJRhEXxOrJxupWM4I3N4deMop+ulxezxlLxIRUz7ELc+6WucYXgOnAA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.6.0", - "@typespec/http": "^1.6.0" + "@typespec/compiler": "^1.7.0", + "@typespec/http": "^1.7.0" } }, "node_modules/@typespec/spec-api": { - "version": "0.1.0-alpha.10", - "resolved": "https://registry.npmjs.org/@typespec/spec-api/-/spec-api-0.1.0-alpha.10.tgz", - "integrity": "sha512-LvwlhMnwqzCjmwOPuoE1jPfK+474qmo29Jq4Da2FZkjZbDsbyWuU4FRptRMhjsNj3ITMz/VulShXq4eXz4VroQ==", + "version": "0.1.0-alpha.11", + "resolved": "https://registry.npmjs.org/@typespec/spec-api/-/spec-api-0.1.0-alpha.11.tgz", + "integrity": "sha512-qNQ8Oc7ha9MzRMfcF4djRaxa7gmM9CUetNeZIVJO4PZDIe9Rb/HMX9C3LP0f5LiiYkE8KvA/jLAR4FSYqp0onA==", "dev": true, "license": "MIT", "dependencies": { @@ -2386,24 +2735,24 @@ } }, "node_modules/@typespec/spec-coverage-sdk": { - "version": "0.1.0-alpha.12", - "resolved": "https://registry.npmjs.org/@typespec/spec-coverage-sdk/-/spec-coverage-sdk-0.1.0-alpha.12.tgz", - "integrity": "sha512-eqzNQ+bZn25SP8GZyf6qgCwXL1U5/OF5AvKFl7AlYfSSuB0ybeWaDQ14jZzl5gnFXY8lCc8P0ycK1HjtwdGyqw==", + "version": "0.1.0-alpha.13", + "resolved": "https://registry.npmjs.org/@typespec/spec-coverage-sdk/-/spec-coverage-sdk-0.1.0-alpha.13.tgz", + "integrity": "sha512-GpCWrbcMQis+utHukdWdY85lNeQX89OBYiBovOxCGO5DmUmqnPQWzHZIggoAQ6fuSlC+tZoWAbY5hygN1QzPPA==", "dev": true, "license": "MIT", "dependencies": { "@azure/identity": "~4.13.0", "@azure/storage-blob": "~12.29.1", - "@types/node": "~24.9.1" + "@types/node": "~24.10.1" }, "engines": { "node": ">=16.0.0" } }, "node_modules/@typespec/spec-coverage-sdk/node_modules/@types/node": { - "version": "24.9.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.9.2.tgz", - "integrity": "sha512-uWN8YqxXxqFMX2RqGOrumsKeti4LlmIMIyV0lgut4jx7KQBcBiW6vkDtIBvHnHIquwNfJhk8v2OtmO8zXWHfPA==", + "version": "24.10.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.3.tgz", + "integrity": "sha512-gqkrWUsS8hcm0r44yn7/xZeV1ERva/nLgrLxFRUGb7aoNMIJfZJ3AC261zDQuOAKC7MiXai1WCpYc48jAHoShQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2453,6 +2802,33 @@ "node": ">=16.0.0" } }, + "node_modules/@typespec/spector/node_modules/@typespec/rest": { + "version": "0.76.0", + "resolved": "https://registry.npmjs.org/@typespec/rest/-/rest-0.76.0.tgz", + "integrity": "sha512-6jtQWdcmuKyG9cmqWsJjaq64f6N5B/1DS4X3ZoTNgYhHA27Hnsxo1HZWXcpv7Wl+MxLAZM6kgpML0ugDEZcrYQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@typespec/compiler": "^1.6.0", + "@typespec/http": "^1.6.0" + } + }, + "node_modules/@typespec/spector/node_modules/@typespec/versioning": { + "version": "0.76.0", + "resolved": "https://registry.npmjs.org/@typespec/versioning/-/versioning-0.76.0.tgz", + "integrity": "sha512-dguO/B+mwlCyenWGG+M+16cMQuGHSTJbU5Z0pyUou1uyWrB1px//s4pW7PKD14S+fPutJE0wTMQm+CctOq6quA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@typespec/compiler": "^1.6.0" + } + }, "node_modules/@typespec/spector/node_modules/ajv": { "version": "8.17.1", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", @@ -2470,19 +2846,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@typespec/spector/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/@typespec/spector/node_modules/cliui": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", @@ -2523,24 +2886,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@typespec/spector/node_modules/wrap-ansi": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", - "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/@typespec/spector/node_modules/yargs": { "version": "18.0.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", @@ -2570,9 +2915,9 @@ } }, "node_modules/@typespec/sse": { - "version": "0.76.0", - "resolved": "https://registry.npmjs.org/@typespec/sse/-/sse-0.76.0.tgz", - "integrity": "sha512-mCd4oAXr0Tt990T2PDjx+6H0jmPHINyCH0XRU2HrWtGW5lG/NQVIs5oOxElc7NGg629HrolfLTw0oW8hdMD7Eg==", + "version": "0.77.0", + "resolved": "https://registry.npmjs.org/@typespec/sse/-/sse-0.77.0.tgz", + "integrity": "sha512-rVML/sPNj+MomKXftko/eUNM5OhHlIevoit3Dbtaf1aWS5pcJ5jKX05Prz53VIyeUP7ra5ocmPE/iIEPb8ZbCA==", "dev": true, "license": "MIT", "peer": true, @@ -2580,24 +2925,23 @@ "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.6.0", - "@typespec/events": "^0.76.0", - "@typespec/http": "^1.6.0", - "@typespec/streams": "^0.76.0" + "@typespec/compiler": "^1.7.0", + "@typespec/events": "^0.77.0", + "@typespec/http": "^1.7.0", + "@typespec/streams": "^0.77.0" } }, "node_modules/@typespec/streams": { - "version": "0.76.0", - "resolved": "https://registry.npmjs.org/@typespec/streams/-/streams-0.76.0.tgz", - "integrity": "sha512-7gQPtsokyn0Mjr43MAik6ZkQt1PZjseU+KcBE2iGT9P6oWYYTH3K1C4LLGXHZAbgEtBvFn4S+U8HPbDhj4nEhw==", + "version": "0.77.0", + "resolved": "https://registry.npmjs.org/@typespec/streams/-/streams-0.77.0.tgz", + "integrity": "sha512-qqfJW4n19Jgi5FxQhsEgoIc5zD9o47AAoZxLKUX91z6aB/YWrLSTrrrIAvhNCESXuB89zlJPwlZ/j4YmpxZ/jw==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.6.0" + "@typespec/compiler": "^1.7.0" } }, "node_modules/@typespec/ts-http-runtime": { @@ -2644,19 +2988,6 @@ "node": ">=20.0.0" } }, - "node_modules/@typespec/tspd/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/@typespec/tspd/node_modules/cliui": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", @@ -2697,24 +3028,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@typespec/tspd/node_modules/wrap-ansi": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", - "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/@typespec/tspd/node_modules/yargs": { "version": "18.0.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", @@ -2744,31 +3057,29 @@ } }, "node_modules/@typespec/versioning": { - "version": "0.76.0", - "resolved": "https://registry.npmjs.org/@typespec/versioning/-/versioning-0.76.0.tgz", - "integrity": "sha512-dguO/B+mwlCyenWGG+M+16cMQuGHSTJbU5Z0pyUou1uyWrB1px//s4pW7PKD14S+fPutJE0wTMQm+CctOq6quA==", + "version": "0.77.0", + "resolved": "https://registry.npmjs.org/@typespec/versioning/-/versioning-0.77.0.tgz", + "integrity": "sha512-eAInPZYPkxpBUS8IKQfNZ5eZsLfkWqEX0d6YM/AfooGYbxcKdHQBfYOWBvRC4NkKEMub4ROaD5GcPLYTyWQIWw==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.6.0" + "@typespec/compiler": "^1.7.0" } }, "node_modules/@typespec/xml": { - "version": "0.76.0", - "resolved": "https://registry.npmjs.org/@typespec/xml/-/xml-0.76.0.tgz", - "integrity": "sha512-+I7hdWZDO3qBfzRT3St+1Dg/NQAMNLz8w1OydutSnVMx0G3KWg/ESonaByszBUfdq6Z5iTtls3gvj4wgrw80gA==", + "version": "0.77.0", + "resolved": "https://registry.npmjs.org/@typespec/xml/-/xml-0.77.0.tgz", + "integrity": "sha512-DNVAOMaRUPGpLEsqf3sn7UAWuAE1rs8Jf1FIAU7DF/sVmzeXs4OBanxSSsVmbcdfPRHPbjPuRnW6e+QS2Sjk3Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.6.0" + "@typespec/compiler": "^1.7.0" } }, "node_modules/@vitest/coverage-v8": { @@ -2884,7 +3195,6 @@ "integrity": "sha512-hGISOaP18plkzbWEcP/QvtRW1xDXF2+96HbEX6byqQhAUbiS5oH6/9JwW+QsQCIYON2bI6QZBF+2PvOmrRZ9wA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@vitest/utils": "3.2.4", "fflate": "^0.8.2", @@ -2963,7 +3273,6 @@ "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -3008,22 +3317,6 @@ } } }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/ansi-regex": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", @@ -3375,9 +3668,9 @@ "license": "MIT" }, "node_modules/chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.1.tgz", + "integrity": "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==", "dev": true, "license": "MIT" }, @@ -4026,34 +4319,6 @@ "url": "https://opencollective.com/express" } }, - "node_modules/external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "license": "MIT", - "dependencies": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/external-editor/node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -4887,6 +5152,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-path-inside": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz", + "integrity": "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-promise": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", @@ -5702,13 +5980,13 @@ } }, "node_modules/mute-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", - "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-3.0.0.tgz", + "integrity": "sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==", "dev": true, "license": "ISC", "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/nanoid": { @@ -5863,16 +6141,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -7218,19 +7486,6 @@ "node": ">=14.0.0" } }, - "node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "license": "MIT", - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -7271,19 +7526,6 @@ "dev": true, "license": "0BSD" }, - "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/type-is": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", @@ -7375,7 +7617,6 @@ "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -7506,14 +7747,6 @@ "url": "https://opencollective.com/vitest" } }, - "node_modules/vite-node/node_modules/undici-types": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz", - "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==", - "dev": true, - "license": "MIT", - "optional": true - }, "node_modules/vite-node/node_modules/vite": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/vite/-/vite-7.0.6.tgz", @@ -7595,7 +7828,6 @@ "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/chai": "^5.2.2", "@vitest/expect": "3.2.4", @@ -7696,7 +7928,6 @@ "integrity": "sha512-MHFiOENNBd+Bd9uvc8GEsIzdkn1JxMmEeYX35tI3fv0sJBUTfW5tQsoaOwuY4KhBI09A3dUJ/DXf2yxPVPUceg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.6", @@ -7909,18 +8140,21 @@ } }, "node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, "node_modules/wrap-ansi-cjs": { @@ -7965,27 +8199,42 @@ "node": ">=8" } }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/wrappy": { @@ -8119,19 +8368,6 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } - }, - "node_modules/yoctocolors-cjs": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz", - "integrity": "sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } } } } diff --git a/packages/http-client-csharp/package.json b/packages/http-client-csharp/package.json index 1e4bdb28e0c..dc0ac6c0245 100644 --- a/packages/http-client-csharp/package.json +++ b/packages/http-client-csharp/package.json @@ -52,31 +52,31 @@ "emitter/lib/*.tsp" ], "peerDependencies": { - "@azure-tools/typespec-client-generator-core": ">=0.62.0 < 0.63.0 || ~0.63.0-0", - "@typespec/compiler": "^1.6.0", - "@typespec/http": "^1.6.0", - "@typespec/openapi": "^1.6.0", - "@typespec/rest": ">=0.76.0 <0.77.0 || ~0.77.0-0", - "@typespec/streams": ">=0.76.0 <0.77.0 || ~0.77.0-0", - "@typespec/versioning": ">=0.76.0 <0.77.0 || ~0.77.0-0" + "@azure-tools/typespec-client-generator-core": ">=0.63.0 < 0.64.0 || ~0.64.0-0", + "@typespec/compiler": "^1.7.0", + "@typespec/http": "^1.7.0", + "@typespec/openapi": "^1.7.0", + "@typespec/rest": ">=0.77.0 <0.78.0 || ~0.78.0-0", + "@typespec/streams": ">=0.77.0 <0.78.0 || ~0.78.0-0", + "@typespec/versioning": ">=0.77.0 <0.78.0 || ~0.78.0-0" }, "devDependencies": { - "@azure-tools/azure-http-specs": "0.1.0-alpha.32", - "@azure-tools/typespec-client-generator-core": "0.62.0", + "@azure-tools/azure-http-specs": "0.1.0-alpha.33", + "@azure-tools/typespec-client-generator-core": "0.63.0", "@microsoft/api-extractor": "^7.52.2", "@types/node": "~22.12.0", - "@typespec/compiler": "1.6.0", - "@typespec/http": "1.6.0", - "@typespec/http-specs": "0.1.0-alpha.28", - "@typespec/json-schema": "1.6.0", - "@typespec/library-linter": "0.76.0", - "@typespec/openapi": "1.6.0", - "@typespec/rest": "0.76.0", + "@typespec/compiler": "1.7.0", + "@typespec/http": "1.7.0", + "@typespec/http-specs": "0.1.0-alpha.29", + "@typespec/json-schema": "1.7.0", + "@typespec/library-linter": "0.77.0", + "@typespec/openapi": "1.7.0", + "@typespec/rest": "0.77.0", "@typespec/spector": "0.1.0-alpha.20", - "@typespec/streams": "0.76.0", + "@typespec/streams": "0.77.0", "@typespec/tspd": "0.73.1", - "@typespec/versioning": "0.76.0", - "@typespec/xml": "0.76.0", + "@typespec/versioning": "0.77.0", + "@typespec/xml": "0.77.0", "@vitest/coverage-v8": "^3.0.5", "@vitest/ui": "^3.0.5", "c8": "^10.1.2", From d76254461e86e1690a02225649545b45b46924dd Mon Sep 17 00:00:00 2001 From: Haoling Dong <87355844+haolingdong-msft@users.noreply.github.com> Date: Fri, 12 Dec 2025 11:53:34 +0800 Subject: [PATCH 31/40] http-client-java, bump typespec and tcgc versions (#9172) Fix https://github.com/microsoft/typespec/issues/9185 Also tried with copilot, but not all dependencies are bumped, try to at copilot but still not correctly updated : https://github.com/microsoft/typespec/pull/9186 ends up to first create a manual PR, and later tune instructions. I'm referring this PR: https://github.com/microsoft/typespec/pull/8993 No breaking changes so bump a patch version --- .../package.json | 36 +- .../DocumentationClientBuilder.java | 249 +++++ .../main/java/documentation/ListsClient.java | 155 +++ .../documentation/TextFormattingClient.java | 133 +++ .../DocumentationClientImpl.java | 94 ++ .../implementation/ListsImpl.java | 163 ++++ .../implementation/TextFormattingsImpl.java | 144 +++ .../implementation/package-info.java | 5 + .../documentation/lists/BulletPointsEnum.java | 85 ++ .../lists/BulletPointsModel.java | 113 +++ .../BulletPointsModelRequest.java | 80 ++ .../lists/implementation/package-info.java | 5 + .../documentation/lists/package-info.java | 5 + .../main/java/documentation/package-info.java | 5 + .../main/java/encode/array/ArrayClient.java | 167 ++++ .../java/encode/array/ArrayClientBuilder.java | 235 +++++ .../array/CommaDelimitedArrayProperty.java | 80 ++ .../array/NewlineDelimitedArrayProperty.java | 80 ++ .../array/PipeDelimitedArrayProperty.java | 80 ++ .../array/SpaceDelimitedArrayProperty.java | 80 ++ .../array/implementation/ArrayClientImpl.java | 79 ++ .../array/implementation/PropertiesImpl.java | 190 ++++ .../array/implementation/package-info.java | 5 + .../main/java/encode/array/package-info.java | 5 + .../specialwords/ModelPropertiesClient.java | 32 + .../implementation/ModelPropertiesImpl.java | 29 + .../modelproperties/DictMethods.java | 278 ++++++ .../documentation_apiview_properties.json | 11 + .../META-INF/documentation_metadata.json | 1 + .../encode-array_apiview_properties.json | 11 + .../META-INF/encode-array_metadata.json | 1 + .../specialwords_apiview_properties.json | 1 + .../META-INF/specialwords_metadata.json | 2 +- .../http-client-generator-test/package.json | 36 +- .../DocumentationClientBuilder.java | 312 ++++++ .../java/documentation/ListsAsyncClient.java | 192 ++++ .../main/java/documentation/ListsClient.java | 187 ++++ .../TextFormattingAsyncClient.java | 154 +++ .../documentation/TextFormattingClient.java | 149 +++ .../DocumentationClientImpl.java | 122 +++ .../implementation/ListsImpl.java | 272 ++++++ .../implementation/TextFormattingsImpl.java | 217 +++++ .../implementation/package-info.java | 11 + .../models/BulletPointsModelRequest.java | 84 ++ .../implementation/models/package-info.java | 11 + .../lists/models/BulletPointsEnum.java | 89 ++ .../lists/models/BulletPointsModel.java | 117 +++ .../lists/models/package-info.java | 11 + .../main/java/documentation/package-info.java | 11 + .../java/encode/array/ArrayAsyncClient.java | 287 ++++++ .../main/java/encode/array/ArrayClient.java | 285 ++++++ .../java/encode/array/ArrayClientBuilder.java | 287 ++++++ .../array/implementation/ArrayClientImpl.java | 107 +++ .../array/implementation/PropertiesImpl.java | 478 ++++++++++ .../array/implementation/package-info.java | 11 + .../models/CommaDelimitedArrayProperty.java | 84 ++ .../models/NewlineDelimitedArrayProperty.java | 84 ++ .../models/PipeDelimitedArrayProperty.java | 84 ++ .../models/SpaceDelimitedArrayProperty.java | 84 ++ .../encode/array/models/package-info.java | 11 + .../main/java/encode/array/package-info.java | 11 + .../ModelPropertiesAsyncClient.java | 56 ++ .../specialwords/ModelPropertiesClient.java | 55 ++ .../implementation/ModelPropertiesImpl.java | 91 ++ .../modelproperties/models/DictMethods.java | 282 ++++++ ...ientinitialization_apiview_properties.json | 156 +-- ...or-core-clientinitialization_metadata.json | 2 +- .../documentation_apiview_properties.json | 37 + .../META-INF/documentation_metadata.json | 1 + .../encode-array_apiview_properties.json | 28 + .../META-INF/encode-array_metadata.json | 1 + .../specialwords_apiview_properties.json | 5 + .../META-INF/specialwords_metadata.json | 2 +- .../main/resources/documentation.properties | 2 + .../main/resources/encode-array.properties | 2 + .../DocumentationClientTestBase.java | 46 + .../array/generated/ArrayClientTestBase.java | 34 + packages/http-client-java/package-lock.json | 898 +++++++++--------- packages/http-client-java/package.json | 58 +- 79 files changed, 7588 insertions(+), 595 deletions(-) create mode 100644 packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/DocumentationClientBuilder.java create mode 100644 packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/ListsClient.java create mode 100644 packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/TextFormattingClient.java create mode 100644 packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/implementation/DocumentationClientImpl.java create mode 100644 packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/implementation/ListsImpl.java create mode 100644 packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/implementation/TextFormattingsImpl.java create mode 100644 packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/implementation/package-info.java create mode 100644 packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/lists/BulletPointsEnum.java create mode 100644 packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/lists/BulletPointsModel.java create mode 100644 packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/lists/implementation/BulletPointsModelRequest.java create mode 100644 packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/lists/implementation/package-info.java create mode 100644 packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/lists/package-info.java create mode 100644 packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/package-info.java create mode 100644 packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/ArrayClient.java create mode 100644 packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/ArrayClientBuilder.java create mode 100644 packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/CommaDelimitedArrayProperty.java create mode 100644 packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/NewlineDelimitedArrayProperty.java create mode 100644 packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/PipeDelimitedArrayProperty.java create mode 100644 packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/SpaceDelimitedArrayProperty.java create mode 100644 packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/implementation/ArrayClientImpl.java create mode 100644 packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/implementation/PropertiesImpl.java create mode 100644 packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/implementation/package-info.java create mode 100644 packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/package-info.java create mode 100644 packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/specialwords/modelproperties/DictMethods.java create mode 100644 packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/resources/META-INF/documentation_apiview_properties.json create mode 100644 packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/resources/META-INF/documentation_metadata.json create mode 100644 packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/resources/META-INF/encode-array_apiview_properties.json create mode 100644 packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/resources/META-INF/encode-array_metadata.json create mode 100644 packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/DocumentationClientBuilder.java create mode 100644 packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/ListsAsyncClient.java create mode 100644 packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/ListsClient.java create mode 100644 packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/TextFormattingAsyncClient.java create mode 100644 packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/TextFormattingClient.java create mode 100644 packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/implementation/DocumentationClientImpl.java create mode 100644 packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/implementation/ListsImpl.java create mode 100644 packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/implementation/TextFormattingsImpl.java create mode 100644 packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/implementation/package-info.java create mode 100644 packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/lists/implementation/models/BulletPointsModelRequest.java create mode 100644 packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/lists/implementation/models/package-info.java create mode 100644 packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/lists/models/BulletPointsEnum.java create mode 100644 packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/lists/models/BulletPointsModel.java create mode 100644 packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/lists/models/package-info.java create mode 100644 packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/package-info.java create mode 100644 packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/ArrayAsyncClient.java create mode 100644 packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/ArrayClient.java create mode 100644 packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/ArrayClientBuilder.java create mode 100644 packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/implementation/ArrayClientImpl.java create mode 100644 packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/implementation/PropertiesImpl.java create mode 100644 packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/implementation/package-info.java create mode 100644 packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/models/CommaDelimitedArrayProperty.java create mode 100644 packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/models/NewlineDelimitedArrayProperty.java create mode 100644 packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/models/PipeDelimitedArrayProperty.java create mode 100644 packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/models/SpaceDelimitedArrayProperty.java create mode 100644 packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/models/package-info.java create mode 100644 packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/package-info.java create mode 100644 packages/http-client-java/generator/http-client-generator-test/src/main/java/specialwords/modelproperties/models/DictMethods.java create mode 100644 packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/documentation_apiview_properties.json create mode 100644 packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/documentation_metadata.json create mode 100644 packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/encode-array_apiview_properties.json create mode 100644 packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/encode-array_metadata.json create mode 100644 packages/http-client-java/generator/http-client-generator-test/src/main/resources/documentation.properties create mode 100644 packages/http-client-java/generator/http-client-generator-test/src/main/resources/encode-array.properties create mode 100644 packages/http-client-java/generator/http-client-generator-test/src/test/java/documentation/generated/DocumentationClientTestBase.java create mode 100644 packages/http-client-java/generator/http-client-generator-test/src/test/java/encode/array/generated/ArrayClientTestBase.java diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/package.json b/packages/http-client-java/generator/http-client-generator-clientcore-test/package.json index 649091a54ae..c11c0a1a842 100644 --- a/packages/http-client-java/generator/http-client-generator-clientcore-test/package.json +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/package.json @@ -12,27 +12,27 @@ "spector-stop": "tsp-spector server stop" }, "dependencies": { - "@typespec/spector": "0.1.0-alpha.20", - "@typespec/spec-api": "0.1.0-alpha.10", - "@typespec/http-specs": "0.1.0-alpha.28", - "@typespec/json-schema": "1.6.0", - "@typespec/http-client-java": "file:../../typespec-http-client-java-0.6.0.tgz", + "@typespec/spector": "0.1.0-alpha.21", + "@typespec/spec-api": "0.1.0-alpha.11", + "@typespec/http-specs": "0.1.0-alpha.29", + "@typespec/json-schema": "1.7.0", + "@typespec/http-client-java": "file:../../typespec-http-client-java-0.6.1.tgz", "@typespec/http-client-java-tests": "file:" }, "overrides": { - "@typespec/compiler": "1.6.0", - "@typespec/http": "1.6.0", - "@typespec/rest": "0.76.0", - "@typespec/versioning": "0.76.0", - "@typespec/openapi": "1.6.0", - "@typespec/xml": "0.76.0", - "@typespec/events": "0.76.0", - "@typespec/sse": "0.76.0", - "@typespec/streams": "0.76.0", - "@azure-tools/typespec-azure-core": "0.62.0", - "@azure-tools/typespec-client-generator-core": "0.62.0", - "@azure-tools/typespec-azure-resource-manager": "0.62.1", - "@azure-tools/typespec-autorest": "0.62.0" + "@typespec/compiler": "1.7.0", + "@typespec/http": "1.7.0", + "@typespec/rest": "0.77.0", + "@typespec/versioning": "0.77.0", + "@typespec/openapi": "1.7.0", + "@typespec/xml": "0.77.0", + "@typespec/events": "0.77.0", + "@typespec/sse": "0.77.0", + "@typespec/streams": "0.77.0", + "@azure-tools/typespec-azure-core": "0.63.0", + "@azure-tools/typespec-client-generator-core": "0.63.0", + "@azure-tools/typespec-azure-resource-manager": "0.63.0", + "@azure-tools/typespec-autorest": "0.63.0" }, "private": true } diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/DocumentationClientBuilder.java b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/DocumentationClientBuilder.java new file mode 100644 index 00000000000..b7f23508991 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/DocumentationClientBuilder.java @@ -0,0 +1,249 @@ +package documentation; + +import documentation.implementation.DocumentationClientImpl; +import io.clientcore.core.annotations.Metadata; +import io.clientcore.core.annotations.MetadataProperties; +import io.clientcore.core.annotations.ServiceClientBuilder; +import io.clientcore.core.http.client.HttpClient; +import io.clientcore.core.http.models.ProxyOptions; +import io.clientcore.core.http.pipeline.HttpInstrumentationOptions; +import io.clientcore.core.http.pipeline.HttpInstrumentationPolicy; +import io.clientcore.core.http.pipeline.HttpPipeline; +import io.clientcore.core.http.pipeline.HttpPipelineBuilder; +import io.clientcore.core.http.pipeline.HttpPipelinePolicy; +import io.clientcore.core.http.pipeline.HttpRedirectOptions; +import io.clientcore.core.http.pipeline.HttpRedirectPolicy; +import io.clientcore.core.http.pipeline.HttpRetryOptions; +import io.clientcore.core.http.pipeline.HttpRetryPolicy; +import io.clientcore.core.instrumentation.Instrumentation; +import io.clientcore.core.instrumentation.SdkInstrumentationOptions; +import io.clientcore.core.traits.ConfigurationTrait; +import io.clientcore.core.traits.EndpointTrait; +import io.clientcore.core.traits.HttpTrait; +import io.clientcore.core.traits.ProxyTrait; +import io.clientcore.core.utils.CoreUtils; +import io.clientcore.core.utils.configuration.Configuration; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * A builder for creating a new instance of the DocumentationClient type. + */ +@ServiceClientBuilder(serviceClients = { ListsClient.class, TextFormattingClient.class }) +public final class DocumentationClientBuilder + implements HttpTrait, ProxyTrait, + ConfigurationTrait, EndpointTrait { + @Metadata(properties = { MetadataProperties.GENERATED }) + private static final String SDK_NAME = "name"; + + @Metadata(properties = { MetadataProperties.GENERATED }) + private static final String SDK_VERSION = "version"; + + @Metadata(properties = { MetadataProperties.GENERATED }) + private static final Map PROPERTIES = CoreUtils.getProperties("documentation.properties"); + + @Metadata(properties = { MetadataProperties.GENERATED }) + private final List pipelinePolicies; + + /** + * Create an instance of the DocumentationClientBuilder. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + public DocumentationClientBuilder() { + this.pipelinePolicies = new ArrayList<>(); + } + + /* + * The HTTP client used to send the request. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + private HttpClient httpClient; + + /** + * {@inheritDoc}. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @Override + public DocumentationClientBuilder httpClient(HttpClient httpClient) { + this.httpClient = httpClient; + return this; + } + + /* + * The retry options to configure retry policy for failed requests. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + private HttpRetryOptions retryOptions; + + /** + * {@inheritDoc}. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @Override + public DocumentationClientBuilder httpRetryOptions(HttpRetryOptions retryOptions) { + this.retryOptions = retryOptions; + return this; + } + + /** + * {@inheritDoc}. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @Override + public DocumentationClientBuilder addHttpPipelinePolicy(HttpPipelinePolicy customPolicy) { + Objects.requireNonNull(customPolicy, "'customPolicy' cannot be null."); + pipelinePolicies.add(customPolicy); + return this; + } + + /* + * The redirect options to configure redirect policy + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + private HttpRedirectOptions redirectOptions; + + /** + * {@inheritDoc}. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @Override + public DocumentationClientBuilder httpRedirectOptions(HttpRedirectOptions redirectOptions) { + this.redirectOptions = redirectOptions; + return this; + } + + /* + * The instrumentation configuration for HTTP requests and responses. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + private HttpInstrumentationOptions httpInstrumentationOptions; + + /** + * {@inheritDoc}. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @Override + public DocumentationClientBuilder + httpInstrumentationOptions(HttpInstrumentationOptions httpInstrumentationOptions) { + this.httpInstrumentationOptions = httpInstrumentationOptions; + return this; + } + + /* + * The proxy options used during construction of the service client. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + private ProxyOptions proxyOptions; + + /** + * {@inheritDoc}. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @Override + public DocumentationClientBuilder proxyOptions(ProxyOptions proxyOptions) { + this.proxyOptions = proxyOptions; + return this; + } + + /* + * The configuration store that is used during construction of the service client. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + private Configuration configuration; + + /** + * {@inheritDoc}. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @Override + public DocumentationClientBuilder configuration(Configuration configuration) { + this.configuration = configuration; + return this; + } + + /* + * The service endpoint + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + private String endpoint; + + /** + * {@inheritDoc}. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @Override + public DocumentationClientBuilder endpoint(String endpoint) { + this.endpoint = endpoint; + return this; + } + + /** + * Builds an instance of DocumentationClientImpl with the provided parameters. + * + * @return an instance of DocumentationClientImpl. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + private DocumentationClientImpl buildInnerClient() { + this.validateClient(); + String localEndpoint = (endpoint != null) ? endpoint : "http://localhost:3000"; + HttpInstrumentationOptions localHttpInstrumentationOptions = this.httpInstrumentationOptions == null + ? new HttpInstrumentationOptions() + : this.httpInstrumentationOptions; + SdkInstrumentationOptions sdkInstrumentationOptions + = new SdkInstrumentationOptions(PROPERTIES.getOrDefault(SDK_NAME, "UnknownName")) + .setSdkVersion(PROPERTIES.get(SDK_VERSION)) + .setEndpoint(localEndpoint); + Instrumentation instrumentation + = Instrumentation.create(localHttpInstrumentationOptions, sdkInstrumentationOptions); + DocumentationClientImpl client + = new DocumentationClientImpl(createHttpPipeline(), instrumentation, localEndpoint); + return client; + } + + @Metadata(properties = { MetadataProperties.GENERATED }) + private void validateClient() { + // This method is invoked from 'buildInnerClient'/'buildClient' method. + // Developer can customize this method, to validate that the necessary conditions are met for the new client. + } + + @Metadata(properties = { MetadataProperties.GENERATED }) + private HttpPipeline createHttpPipeline() { + Configuration buildConfiguration + = (configuration == null) ? Configuration.getGlobalConfiguration() : configuration; + HttpInstrumentationOptions localHttpInstrumentationOptions = this.httpInstrumentationOptions == null + ? new HttpInstrumentationOptions() + : this.httpInstrumentationOptions; + HttpPipelineBuilder httpPipelineBuilder = new HttpPipelineBuilder(); + List policies = new ArrayList<>(); + policies.add(redirectOptions == null ? new HttpRedirectPolicy() : new HttpRedirectPolicy(redirectOptions)); + policies.add(retryOptions == null ? new HttpRetryPolicy() : new HttpRetryPolicy(retryOptions)); + this.pipelinePolicies.stream().forEach(p -> policies.add(p)); + policies.add(new HttpInstrumentationPolicy(localHttpInstrumentationOptions)); + policies.forEach(httpPipelineBuilder::addPolicy); + return httpPipelineBuilder.httpClient(httpClient).build(); + } + + /** + * Builds an instance of ListsClient class. + * + * @return an instance of ListsClient. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + public ListsClient buildListsClient() { + DocumentationClientImpl innerClient = buildInnerClient(); + return new ListsClient(innerClient.getLists(), innerClient.getInstrumentation()); + } + + /** + * Builds an instance of TextFormattingClient class. + * + * @return an instance of TextFormattingClient. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + public TextFormattingClient buildTextFormattingClient() { + DocumentationClientImpl innerClient = buildInnerClient(); + return new TextFormattingClient(innerClient.getTextFormattings(), innerClient.getInstrumentation()); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/ListsClient.java b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/ListsClient.java new file mode 100644 index 00000000000..9beabb61a6a --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/ListsClient.java @@ -0,0 +1,155 @@ +package documentation; + +import documentation.implementation.ListsImpl; +import documentation.lists.BulletPointsModel; +import io.clientcore.core.annotations.Metadata; +import io.clientcore.core.annotations.MetadataProperties; +import io.clientcore.core.annotations.ReturnType; +import io.clientcore.core.annotations.ServiceClient; +import io.clientcore.core.annotations.ServiceMethod; +import io.clientcore.core.http.models.HttpResponseException; +import io.clientcore.core.http.models.RequestContext; +import io.clientcore.core.http.models.Response; +import io.clientcore.core.instrumentation.Instrumentation; + +/** + * Initializes a new instance of the synchronous DocumentationClient type. + */ +@ServiceClient(builder = DocumentationClientBuilder.class) +public final class ListsClient { + @Metadata(properties = { MetadataProperties.GENERATED }) + private final ListsImpl serviceClient; + + private final Instrumentation instrumentation; + + /** + * Initializes an instance of ListsClient class. + * + * @param serviceClient the service client implementation. + * @param instrumentation the instrumentation instance. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + ListsClient(ListsImpl serviceClient, Instrumentation instrumentation) { + this.serviceClient = serviceClient; + this.instrumentation = instrumentation; + } + + /** + * This tests: + * - Simple bullet point. This bullet point is going to be very long to test how text wrapping is handled in bullet + * points within documentation comments. It should properly indent the wrapped lines. + * - Another bullet point with **bold text**. This bullet point is also intentionally long to see how the formatting + * is preserved when the text wraps onto multiple lines in the generated documentation. + * - Third bullet point with *italic text*. Similar to the previous points, this one is extended to ensure that the + * wrapping and formatting are correctly applied in the output. + * - Complex bullet point with **bold** and *italic* combined. This bullet point combines both bold and italic + * formatting and is long enough to test the wrapping behavior in such cases. + * - **Bold bullet point**: A bullet point that is entirely bolded. This point is also made lengthy to observe how + * the bold formatting is maintained across wrapped lines. + * - *Italic bullet point*: A bullet point that is entirely italicized. This final point is extended to verify that + * italic formatting is correctly applied even when the text spans multiple lines. + * + * @param requestContext The context to configure the HTTP request before HTTP client sends it. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the service returns an error. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the {@link Response}. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @ServiceMethod(returns = ReturnType.SINGLE) + public Response bulletPointsOpWithResponse(RequestContext requestContext) { + return this.instrumentation.instrumentWithResponse("Documentation.Lists.bulletPointsOp", requestContext, + updatedContext -> this.serviceClient.bulletPointsOpWithResponse(updatedContext)); + } + + /** + * This tests: + * - Simple bullet point. This bullet point is going to be very long to test how text wrapping is handled in bullet + * points within documentation comments. It should properly indent the wrapped lines. + * - Another bullet point with **bold text**. This bullet point is also intentionally long to see how the formatting + * is preserved when the text wraps onto multiple lines in the generated documentation. + * - Third bullet point with *italic text*. Similar to the previous points, this one is extended to ensure that the + * wrapping and formatting are correctly applied in the output. + * - Complex bullet point with **bold** and *italic* combined. This bullet point combines both bold and italic + * formatting and is long enough to test the wrapping behavior in such cases. + * - **Bold bullet point**: A bullet point that is entirely bolded. This point is also made lengthy to observe how + * the bold formatting is maintained across wrapped lines. + * - *Italic bullet point*: A bullet point that is entirely italicized. This final point is extended to verify that + * italic formatting is correctly applied even when the text spans multiple lines. + * + * @throws HttpResponseException thrown if the service returns an error. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @ServiceMethod(returns = ReturnType.SINGLE) + public void bulletPointsOp() { + bulletPointsOpWithResponse(RequestContext.none()); + } + + /** + * The bulletPointsModel operation. + * + * @param input The input parameter. + * @param requestContext The context to configure the HTTP request before HTTP client sends it. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the service returns an error. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the {@link Response}. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @ServiceMethod(returns = ReturnType.SINGLE) + public Response bulletPointsModelWithResponse(BulletPointsModel input, RequestContext requestContext) { + return this.instrumentation.instrumentWithResponse("Documentation.Lists.bulletPointsModel", requestContext, + updatedContext -> this.serviceClient.bulletPointsModelWithResponse(input, updatedContext)); + } + + /** + * The bulletPointsModel operation. + * + * @param input The input parameter. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the service returns an error. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @ServiceMethod(returns = ReturnType.SINGLE) + public void bulletPointsModel(BulletPointsModel input) { + bulletPointsModelWithResponse(input, RequestContext.none()); + } + + /** + * Steps to follow: + * 1. First step with **important** note + * 2. Second step with *emphasis* + * 3. Third step combining **bold** and *italic* + * 4. **Final step**: Review all steps for *accuracy*. + * + * @param requestContext The context to configure the HTTP request before HTTP client sends it. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the service returns an error. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the {@link Response}. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @ServiceMethod(returns = ReturnType.SINGLE) + public Response numberedWithResponse(RequestContext requestContext) { + return this.instrumentation.instrumentWithResponse("Documentation.Lists.numbered", requestContext, + updatedContext -> this.serviceClient.numberedWithResponse(updatedContext)); + } + + /** + * Steps to follow: + * 1. First step with **important** note + * 2. Second step with *emphasis* + * 3. Third step combining **bold** and *italic* + * 4. **Final step**: Review all steps for *accuracy*. + * + * @throws HttpResponseException thrown if the service returns an error. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @ServiceMethod(returns = ReturnType.SINGLE) + public void numbered() { + numberedWithResponse(RequestContext.none()); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/TextFormattingClient.java b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/TextFormattingClient.java new file mode 100644 index 00000000000..efaffa55e63 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/TextFormattingClient.java @@ -0,0 +1,133 @@ +package documentation; + +import documentation.implementation.TextFormattingsImpl; +import io.clientcore.core.annotations.Metadata; +import io.clientcore.core.annotations.MetadataProperties; +import io.clientcore.core.annotations.ReturnType; +import io.clientcore.core.annotations.ServiceClient; +import io.clientcore.core.annotations.ServiceMethod; +import io.clientcore.core.http.models.HttpResponseException; +import io.clientcore.core.http.models.RequestContext; +import io.clientcore.core.http.models.Response; +import io.clientcore.core.instrumentation.Instrumentation; + +/** + * Initializes a new instance of the synchronous DocumentationClient type. + */ +@ServiceClient(builder = DocumentationClientBuilder.class) +public final class TextFormattingClient { + @Metadata(properties = { MetadataProperties.GENERATED }) + private final TextFormattingsImpl serviceClient; + + private final Instrumentation instrumentation; + + /** + * Initializes an instance of TextFormattingClient class. + * + * @param serviceClient the service client implementation. + * @param instrumentation the instrumentation instance. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + TextFormattingClient(TextFormattingsImpl serviceClient, Instrumentation instrumentation) { + this.serviceClient = serviceClient; + this.instrumentation = instrumentation; + } + + /** + * This is **bold text** in the middle of a sentence. + * This is a sentence with **multiple bold** sections and **another bold** section. + * **This entire sentence is bold.**. + * + * @param requestContext The context to configure the HTTP request before HTTP client sends it. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the service returns an error. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the {@link Response}. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @ServiceMethod(returns = ReturnType.SINGLE) + public Response boldTextWithResponse(RequestContext requestContext) { + return this.instrumentation.instrumentWithResponse("Documentation.TextFormatting.boldText", requestContext, + updatedContext -> this.serviceClient.boldTextWithResponse(updatedContext)); + } + + /** + * This is **bold text** in the middle of a sentence. + * This is a sentence with **multiple bold** sections and **another bold** section. + * **This entire sentence is bold.**. + * + * @throws HttpResponseException thrown if the service returns an error. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @ServiceMethod(returns = ReturnType.SINGLE) + public void boldText() { + boldTextWithResponse(RequestContext.none()); + } + + /** + * This is *italic text* in the middle of a sentence. + * This is a sentence with *multiple italic* sections and *another italic* section. + * *This entire sentence is italic.*. + * + * @param requestContext The context to configure the HTTP request before HTTP client sends it. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the service returns an error. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the {@link Response}. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @ServiceMethod(returns = ReturnType.SINGLE) + public Response italicTextWithResponse(RequestContext requestContext) { + return this.instrumentation.instrumentWithResponse("Documentation.TextFormatting.italicText", requestContext, + updatedContext -> this.serviceClient.italicTextWithResponse(updatedContext)); + } + + /** + * This is *italic text* in the middle of a sentence. + * This is a sentence with *multiple italic* sections and *another italic* section. + * *This entire sentence is italic.*. + * + * @throws HttpResponseException thrown if the service returns an error. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @ServiceMethod(returns = ReturnType.SINGLE) + public void italicText() { + italicTextWithResponse(RequestContext.none()); + } + + /** + * This sentence has **bold**, *italic*, and ***bold italic*** text. + * You can also combine them like **bold with *italic inside* bold**. + * Or *italic with **bold inside** italic*. + * This is a sentence with **bold**, *italic*, and ***bold italic*** text. + * + * @param requestContext The context to configure the HTTP request before HTTP client sends it. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the service returns an error. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the {@link Response}. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @ServiceMethod(returns = ReturnType.SINGLE) + public Response combinedFormattingWithResponse(RequestContext requestContext) { + return this.instrumentation.instrumentWithResponse("Documentation.TextFormatting.combinedFormatting", + requestContext, updatedContext -> this.serviceClient.combinedFormattingWithResponse(updatedContext)); + } + + /** + * This sentence has **bold**, *italic*, and ***bold italic*** text. + * You can also combine them like **bold with *italic inside* bold**. + * Or *italic with **bold inside** italic*. + * This is a sentence with **bold**, *italic*, and ***bold italic*** text. + * + * @throws HttpResponseException thrown if the service returns an error. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @ServiceMethod(returns = ReturnType.SINGLE) + public void combinedFormatting() { + combinedFormattingWithResponse(RequestContext.none()); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/implementation/DocumentationClientImpl.java b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/implementation/DocumentationClientImpl.java new file mode 100644 index 00000000000..e65576af6fb --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/implementation/DocumentationClientImpl.java @@ -0,0 +1,94 @@ +package documentation.implementation; + +import io.clientcore.core.http.pipeline.HttpPipeline; +import io.clientcore.core.instrumentation.Instrumentation; + +/** + * Initializes a new instance of the DocumentationClient type. + */ +public final class DocumentationClientImpl { + /** + * Service host. + */ + private final String endpoint; + + /** + * Gets Service host. + * + * @return the endpoint value. + */ + public String getEndpoint() { + return this.endpoint; + } + + /** + * The HTTP pipeline to send requests through. + */ + private final HttpPipeline httpPipeline; + + /** + * Gets The HTTP pipeline to send requests through. + * + * @return the httpPipeline value. + */ + public HttpPipeline getHttpPipeline() { + return this.httpPipeline; + } + + /** + * The instance of instrumentation to report telemetry. + */ + private final Instrumentation instrumentation; + + /** + * Gets The instance of instrumentation to report telemetry. + * + * @return the instrumentation value. + */ + public Instrumentation getInstrumentation() { + return this.instrumentation; + } + + /** + * The ListsImpl object to access its operations. + */ + private final ListsImpl lists; + + /** + * Gets the ListsImpl object to access its operations. + * + * @return the ListsImpl object. + */ + public ListsImpl getLists() { + return this.lists; + } + + /** + * The TextFormattingsImpl object to access its operations. + */ + private final TextFormattingsImpl textFormattings; + + /** + * Gets the TextFormattingsImpl object to access its operations. + * + * @return the TextFormattingsImpl object. + */ + public TextFormattingsImpl getTextFormattings() { + return this.textFormattings; + } + + /** + * Initializes an instance of DocumentationClient client. + * + * @param httpPipeline The HTTP pipeline to send requests through. + * @param instrumentation The instance of instrumentation to report telemetry. + * @param endpoint Service host. + */ + public DocumentationClientImpl(HttpPipeline httpPipeline, Instrumentation instrumentation, String endpoint) { + this.httpPipeline = httpPipeline; + this.instrumentation = instrumentation; + this.endpoint = endpoint; + this.lists = new ListsImpl(this); + this.textFormattings = new TextFormattingsImpl(this); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/implementation/ListsImpl.java b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/implementation/ListsImpl.java new file mode 100644 index 00000000000..d10752503fe --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/implementation/ListsImpl.java @@ -0,0 +1,163 @@ +package documentation.implementation; + +import documentation.lists.BulletPointsModel; +import documentation.lists.implementation.BulletPointsModelRequest; +import io.clientcore.core.annotations.ReturnType; +import io.clientcore.core.annotations.ServiceInterface; +import io.clientcore.core.annotations.ServiceMethod; +import io.clientcore.core.http.annotations.BodyParam; +import io.clientcore.core.http.annotations.HeaderParam; +import io.clientcore.core.http.annotations.HostParam; +import io.clientcore.core.http.annotations.HttpRequestInformation; +import io.clientcore.core.http.annotations.UnexpectedResponseExceptionDetail; +import io.clientcore.core.http.models.HttpMethod; +import io.clientcore.core.http.models.HttpResponseException; +import io.clientcore.core.http.models.RequestContext; +import io.clientcore.core.http.models.Response; +import io.clientcore.core.http.pipeline.HttpPipeline; +import io.clientcore.core.instrumentation.Instrumentation; +import java.lang.reflect.InvocationTargetException; + +/** + * An instance of this class provides access to all the operations defined in Lists. + */ +public final class ListsImpl { + /** + * The proxy service used to perform REST calls. + */ + private final ListsService service; + + /** + * The service client containing this operation class. + */ + private final DocumentationClientImpl client; + + /** + * The instance of instrumentation to report telemetry. + */ + private final Instrumentation instrumentation; + + /** + * Initializes an instance of ListsImpl. + * + * @param client the instance of the service client containing this operation class. + */ + ListsImpl(DocumentationClientImpl client) { + this.service = ListsService.getNewInstance(client.getHttpPipeline()); + this.client = client; + this.instrumentation = client.getInstrumentation(); + } + + /** + * The interface defining all the services for DocumentationClientLists to be used by the proxy service to perform + * REST calls. + */ + @ServiceInterface(name = "DocumentationClientLists", host = "{endpoint}") + public interface ListsService { + static ListsService getNewInstance(HttpPipeline pipeline) { + try { + Class clazz = Class.forName("documentation.implementation.ListsServiceImpl"); + return (ListsService) clazz.getMethod("getNewInstance", HttpPipeline.class).invoke(null, pipeline); + } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException + | InvocationTargetException e) { + throw new RuntimeException(e); + } + + } + + @HttpRequestInformation( + method = HttpMethod.GET, + path = "/documentation/lists/bullet-points/op", + expectedStatusCodes = { 204 }) + @UnexpectedResponseExceptionDetail + Response bulletPointsOp(@HostParam("endpoint") String endpoint, RequestContext requestContext); + + @HttpRequestInformation( + method = HttpMethod.POST, + path = "/documentation/lists/bullet-points/model", + expectedStatusCodes = { 204 }) + @UnexpectedResponseExceptionDetail + Response bulletPointsModel(@HostParam("endpoint") String endpoint, + @HeaderParam("Content-Type") String contentType, + @BodyParam("application/json") BulletPointsModelRequest bulletPointsModelRequest, + RequestContext requestContext); + + @HttpRequestInformation( + method = HttpMethod.GET, + path = "/documentation/lists/numbered", + expectedStatusCodes = { 204 }) + @UnexpectedResponseExceptionDetail + Response numbered(@HostParam("endpoint") String endpoint, RequestContext requestContext); + } + + /** + * This tests: + * - Simple bullet point. This bullet point is going to be very long to test how text wrapping is handled in bullet + * points within documentation comments. It should properly indent the wrapped lines. + * - Another bullet point with **bold text**. This bullet point is also intentionally long to see how the formatting + * is preserved when the text wraps onto multiple lines in the generated documentation. + * - Third bullet point with *italic text*. Similar to the previous points, this one is extended to ensure that the + * wrapping and formatting are correctly applied in the output. + * - Complex bullet point with **bold** and *italic* combined. This bullet point combines both bold and italic + * formatting and is long enough to test the wrapping behavior in such cases. + * - **Bold bullet point**: A bullet point that is entirely bolded. This point is also made lengthy to observe how + * the bold formatting is maintained across wrapped lines. + * - *Italic bullet point*: A bullet point that is entirely italicized. This final point is extended to verify that + * italic formatting is correctly applied even when the text spans multiple lines. + * + * @param requestContext The context to configure the HTTP request before HTTP client sends it. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the service returns an error. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response bulletPointsOpWithResponse(RequestContext requestContext) { + return this.instrumentation.instrumentWithResponse("Documentation.Lists.bulletPointsOp", requestContext, + updatedContext -> { + return service.bulletPointsOp(this.client.getEndpoint(), updatedContext); + }); + } + + /** + * The bulletPointsModel operation. + * + * @param input The input parameter. + * @param requestContext The context to configure the HTTP request before HTTP client sends it. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the service returns an error. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response bulletPointsModelWithResponse(BulletPointsModel input, RequestContext requestContext) { + return this.instrumentation.instrumentWithResponse("Documentation.Lists.bulletPointsModel", requestContext, + updatedContext -> { + final String contentType = "application/json"; + BulletPointsModelRequest bulletPointsModelRequest = new BulletPointsModelRequest(input); + return service.bulletPointsModel(this.client.getEndpoint(), contentType, bulletPointsModelRequest, + updatedContext); + }); + } + + /** + * Steps to follow: + * 1. First step with **important** note + * 2. Second step with *emphasis* + * 3. Third step combining **bold** and *italic* + * 4. **Final step**: Review all steps for *accuracy*. + * + * @param requestContext The context to configure the HTTP request before HTTP client sends it. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the service returns an error. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response numberedWithResponse(RequestContext requestContext) { + return this.instrumentation.instrumentWithResponse("Documentation.Lists.numbered", requestContext, + updatedContext -> { + return service.numbered(this.client.getEndpoint(), updatedContext); + }); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/implementation/TextFormattingsImpl.java b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/implementation/TextFormattingsImpl.java new file mode 100644 index 00000000000..3b3076f04f9 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/implementation/TextFormattingsImpl.java @@ -0,0 +1,144 @@ +package documentation.implementation; + +import io.clientcore.core.annotations.ReturnType; +import io.clientcore.core.annotations.ServiceInterface; +import io.clientcore.core.annotations.ServiceMethod; +import io.clientcore.core.http.annotations.HostParam; +import io.clientcore.core.http.annotations.HttpRequestInformation; +import io.clientcore.core.http.annotations.UnexpectedResponseExceptionDetail; +import io.clientcore.core.http.models.HttpMethod; +import io.clientcore.core.http.models.HttpResponseException; +import io.clientcore.core.http.models.RequestContext; +import io.clientcore.core.http.models.Response; +import io.clientcore.core.http.pipeline.HttpPipeline; +import io.clientcore.core.instrumentation.Instrumentation; +import java.lang.reflect.InvocationTargetException; + +/** + * An instance of this class provides access to all the operations defined in TextFormattings. + */ +public final class TextFormattingsImpl { + /** + * The proxy service used to perform REST calls. + */ + private final TextFormattingsService service; + + /** + * The service client containing this operation class. + */ + private final DocumentationClientImpl client; + + /** + * The instance of instrumentation to report telemetry. + */ + private final Instrumentation instrumentation; + + /** + * Initializes an instance of TextFormattingsImpl. + * + * @param client the instance of the service client containing this operation class. + */ + TextFormattingsImpl(DocumentationClientImpl client) { + this.service = TextFormattingsService.getNewInstance(client.getHttpPipeline()); + this.client = client; + this.instrumentation = client.getInstrumentation(); + } + + /** + * The interface defining all the services for DocumentationClientTextFormattings to be used by the proxy service to + * perform REST calls. + */ + @ServiceInterface(name = "DocumentationClientTextFormattings", host = "{endpoint}") + public interface TextFormattingsService { + static TextFormattingsService getNewInstance(HttpPipeline pipeline) { + try { + Class clazz = Class.forName("documentation.implementation.TextFormattingsServiceImpl"); + return (TextFormattingsService) clazz.getMethod("getNewInstance", HttpPipeline.class) + .invoke(null, pipeline); + } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException + | InvocationTargetException e) { + throw new RuntimeException(e); + } + + } + + @HttpRequestInformation( + method = HttpMethod.GET, + path = "/documentation/text-formatting/bold", + expectedStatusCodes = { 204 }) + @UnexpectedResponseExceptionDetail + Response boldText(@HostParam("endpoint") String endpoint, RequestContext requestContext); + + @HttpRequestInformation( + method = HttpMethod.GET, + path = "/documentation/text-formatting/italic", + expectedStatusCodes = { 204 }) + @UnexpectedResponseExceptionDetail + Response italicText(@HostParam("endpoint") String endpoint, RequestContext requestContext); + + @HttpRequestInformation( + method = HttpMethod.GET, + path = "/documentation/text-formatting/combined", + expectedStatusCodes = { 204 }) + @UnexpectedResponseExceptionDetail + Response combinedFormatting(@HostParam("endpoint") String endpoint, RequestContext requestContext); + } + + /** + * This is **bold text** in the middle of a sentence. + * This is a sentence with **multiple bold** sections and **another bold** section. + * **This entire sentence is bold.**. + * + * @param requestContext The context to configure the HTTP request before HTTP client sends it. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the service returns an error. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response boldTextWithResponse(RequestContext requestContext) { + return this.instrumentation.instrumentWithResponse("Documentation.TextFormatting.boldText", requestContext, + updatedContext -> { + return service.boldText(this.client.getEndpoint(), updatedContext); + }); + } + + /** + * This is *italic text* in the middle of a sentence. + * This is a sentence with *multiple italic* sections and *another italic* section. + * *This entire sentence is italic.*. + * + * @param requestContext The context to configure the HTTP request before HTTP client sends it. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the service returns an error. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response italicTextWithResponse(RequestContext requestContext) { + return this.instrumentation.instrumentWithResponse("Documentation.TextFormatting.italicText", requestContext, + updatedContext -> { + return service.italicText(this.client.getEndpoint(), updatedContext); + }); + } + + /** + * This sentence has **bold**, *italic*, and ***bold italic*** text. + * You can also combine them like **bold with *italic inside* bold**. + * Or *italic with **bold inside** italic*. + * This is a sentence with **bold**, *italic*, and ***bold italic*** text. + * + * @param requestContext The context to configure the HTTP request before HTTP client sends it. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the service returns an error. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response combinedFormattingWithResponse(RequestContext requestContext) { + return this.instrumentation.instrumentWithResponse("Documentation.TextFormatting.combinedFormatting", + requestContext, updatedContext -> { + return service.combinedFormatting(this.client.getEndpoint(), updatedContext); + }); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/implementation/package-info.java b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/implementation/package-info.java new file mode 100644 index 00000000000..9c2d02632a3 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/implementation/package-info.java @@ -0,0 +1,5 @@ +/** + * Package containing the implementations for Documentation. + * Illustrates documentation generation and formatting features. + */ +package documentation.implementation; diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/lists/BulletPointsEnum.java b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/lists/BulletPointsEnum.java new file mode 100644 index 00000000000..e4bc0c552db --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/lists/BulletPointsEnum.java @@ -0,0 +1,85 @@ +package documentation.lists; + +/** + * This tests really long bullet points in enum documentation to see how wrapping and formatting are handled. This + * should wrap around correctly and maintain proper indentation for each line. + * - Simple bullet point. This bullet point is going to be very long to test how text wrapping is handled in bullet + * points within documentation comments. It should properly indent the wrapped lines. + * - Another bullet point with **bold text**. This bullet point is also intentionally long to see how the formatting is + * preserved when the text wraps onto multiple lines in the generated documentation. + * - Third bullet point with *italic text*. Similar to the previous points, this one is extended to ensure that the + * wrapping and formatting are correctly applied in the output. + * - Complex bullet point with **bold** and *italic* combined. This bullet point combines both bold and italic + * formatting and is long enough to test the wrapping behavior in such cases. + * - **Bold bullet point**: A bullet point that is entirely bolded. This point is also made lengthy to observe how the + * bold formatting is maintained across wrapped lines. + * - *Italic bullet point*: A bullet point that is entirely italicized. This final point is extended to verify that + * italic formatting is correctly applied even when the text spans multiple lines. + */ +public enum BulletPointsEnum { + /** + * Simple bullet point. This line is intentionally long to test text wrapping in bullet points within enum + * documentation comments. It should properly indent the wrapped lines. + * - One: one. This line is intentionally long to test text wrapping in bullet points within enum documentation + * comments. It should properly indent the wrapped lines. + * - Two: two. This line is intentionally long to test text wrapping in bullet points within enum documentation + * comments. It should properly indent the wrapped lines. + */ + SIMPLE("Simple"), + + /** + * Bullet point with **bold text**. This line is intentionally long to test text wrapping in bullet points within + * enum documentation comments. It should properly indent the wrapped lines. + * - **One**: one. This line is intentionally long to test text wrapping in bullet points within enum documentation + * comments. It should properly indent the wrapped lines. + * - **Two**: two. This line is intentionally long to test text wrapping in bullet points within enum documentation + * comments. It should properly indent the wrapped lines. + */ + BOLD("Bold"), + + /** + * Bullet point with *italic text*. This line is intentionally long to test text wrapping in bullet points within + * enum documentation comments. It should properly indent the wrapped lines. + * - *One*: one. This line is intentionally long to test text wrapping in bullet points within enum documentation + * comments. It should properly indent the wrapped lines. + * - *Two*: two. This line is intentionally long to test text wrapping in bullet points within enum documentation + * comments. It should properly indent the wrapped lines. + */ + ITALIC("Italic"); + + /** + * The actual serialized value for a BulletPointsEnum instance. + */ + private final String value; + + BulletPointsEnum(String value) { + this.value = value; + } + + /** + * Parses a serialized value to a BulletPointsEnum instance. + * + * @param value the serialized value to parse. + * @return the parsed BulletPointsEnum object, or null if unable to parse. + */ + public static BulletPointsEnum fromString(String value) { + if (value == null) { + return null; + } + BulletPointsEnum[] items = BulletPointsEnum.values(); + for (BulletPointsEnum item : items) { + if (item.toString().equalsIgnoreCase(value)) { + return item; + } + } + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return this.value; + } +} diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/lists/BulletPointsModel.java b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/lists/BulletPointsModel.java new file mode 100644 index 00000000000..d16d55ea88c --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/lists/BulletPointsModel.java @@ -0,0 +1,113 @@ +package documentation.lists; + +import io.clientcore.core.annotations.Metadata; +import io.clientcore.core.annotations.MetadataProperties; +import io.clientcore.core.serialization.json.JsonReader; +import io.clientcore.core.serialization.json.JsonSerializable; +import io.clientcore.core.serialization.json.JsonToken; +import io.clientcore.core.serialization.json.JsonWriter; +import java.io.IOException; + +/** + * This tests: + * - Simple bullet point. This bullet point is going to be very long to test how text wrapping is handled in bullet + * points within documentation comments. It should properly indent the wrapped lines. + * - Another bullet point with **bold text**. This bullet point is also intentionally long to see how the formatting is + * preserved when the text wraps onto multiple lines in the generated documentation. + * - Third bullet point with *italic text*. Similar to the previous points, this one is extended to ensure that the + * wrapping and formatting are correctly applied in the output. + * - Complex bullet point with **bold** and *italic* combined. This bullet point combines both bold and italic + * formatting and is long enough to test the wrapping behavior in such cases. + * - **Bold bullet point**: A bullet point that is entirely bolded. This point is also made lengthy to observe how the + * bold formatting is maintained across wrapped lines. + * - *Italic bullet point*: A bullet point that is entirely italicized. This final point is extended to verify that + * italic formatting is correctly applied even when the text spans multiple lines. + */ +@Metadata(properties = { MetadataProperties.IMMUTABLE }) +public final class BulletPointsModel implements JsonSerializable { + /* + * This property uses an enum with bullet point documentation. The enum documentation includes various formatting + * styles to test rendering. The styles are: + * - Simple bullet point. This bullet point is going to be very long to test how text wrapping is handled in bullet + * points within documentation comments. It should properly indent the wrapped lines. + * - Bullet point with **bold text**. This bullet point is also intentionally long to see how the formatting is + * preserved when the text wraps onto multiple + * - Bullet point with *italic text*. Similar to the previous points, this one is extended to ensure that the + * wrapping and formatting are correctly applied in the output. + * - Complex bullet point with **bold** and *italic* combined. This bullet point combines both bold and italic + * formatting and is long enough to test the wrapping behavior in such cases. + * - **Bold bullet point** + * - *Italic bullet point* + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + private final BulletPointsEnum prop; + + /** + * Creates an instance of BulletPointsModel class. + * + * @param prop the prop value to set. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + public BulletPointsModel(BulletPointsEnum prop) { + this.prop = prop; + } + + /** + * Get the prop property: This property uses an enum with bullet point documentation. The enum documentation + * includes various formatting styles to test rendering. The styles are: + * - Simple bullet point. This bullet point is going to be very long to test how text wrapping is handled in bullet + * points within documentation comments. It should properly indent the wrapped lines. + * - Bullet point with **bold text**. This bullet point is also intentionally long to see how the formatting is + * preserved when the text wraps onto multiple + * - Bullet point with *italic text*. Similar to the previous points, this one is extended to ensure that the + * wrapping and formatting are correctly applied in the output. + * - Complex bullet point with **bold** and *italic* combined. This bullet point combines both bold and italic + * formatting and is long enough to test the wrapping behavior in such cases. + * - **Bold bullet point** + * - *Italic bullet point*. + * + * @return the prop value. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + public BulletPointsEnum getProp() { + return this.prop; + } + + /** + * {@inheritDoc} + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + jsonWriter.writeStringField("prop", this.prop == null ? null : this.prop.toString()); + return jsonWriter.writeEndObject(); + } + + /** + * Reads an instance of BulletPointsModel from the JsonReader. + * + * @param jsonReader The JsonReader being read. + * @return An instance of BulletPointsModel if the JsonReader was pointing to an instance of it, or null if it was + * pointing to JSON null. + * @throws IllegalStateException If the deserialized JSON object was missing any required properties. + * @throws IOException If an error occurs while reading the BulletPointsModel. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + public static BulletPointsModel fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject(reader -> { + BulletPointsEnum prop = null; + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("prop".equals(fieldName)) { + prop = BulletPointsEnum.fromString(reader.getString()); + } else { + reader.skipChildren(); + } + } + return new BulletPointsModel(prop); + }); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/lists/implementation/BulletPointsModelRequest.java b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/lists/implementation/BulletPointsModelRequest.java new file mode 100644 index 00000000000..6cc38d35fd8 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/lists/implementation/BulletPointsModelRequest.java @@ -0,0 +1,80 @@ +package documentation.lists.implementation; + +import documentation.lists.BulletPointsModel; +import io.clientcore.core.annotations.Metadata; +import io.clientcore.core.annotations.MetadataProperties; +import io.clientcore.core.serialization.json.JsonReader; +import io.clientcore.core.serialization.json.JsonSerializable; +import io.clientcore.core.serialization.json.JsonToken; +import io.clientcore.core.serialization.json.JsonWriter; +import java.io.IOException; + +/** + * The BulletPointsModelRequest model. + */ +@Metadata(properties = { MetadataProperties.IMMUTABLE }) +public final class BulletPointsModelRequest implements JsonSerializable { + /* + * The input property. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + private final BulletPointsModel input; + + /** + * Creates an instance of BulletPointsModelRequest class. + * + * @param input the input value to set. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + public BulletPointsModelRequest(BulletPointsModel input) { + this.input = input; + } + + /** + * Get the input property: The input property. + * + * @return the input value. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + public BulletPointsModel getInput() { + return this.input; + } + + /** + * {@inheritDoc} + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + jsonWriter.writeJsonField("input", this.input); + return jsonWriter.writeEndObject(); + } + + /** + * Reads an instance of BulletPointsModelRequest from the JsonReader. + * + * @param jsonReader The JsonReader being read. + * @return An instance of BulletPointsModelRequest if the JsonReader was pointing to an instance of it, or null if + * it was pointing to JSON null. + * @throws IllegalStateException If the deserialized JSON object was missing any required properties. + * @throws IOException If an error occurs while reading the BulletPointsModelRequest. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + public static BulletPointsModelRequest fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject(reader -> { + BulletPointsModel input = null; + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("input".equals(fieldName)) { + input = BulletPointsModel.fromJson(reader); + } else { + reader.skipChildren(); + } + } + return new BulletPointsModelRequest(input); + }); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/lists/implementation/package-info.java b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/lists/implementation/package-info.java new file mode 100644 index 00000000000..8a392f51cdb --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/lists/implementation/package-info.java @@ -0,0 +1,5 @@ +/** + * Package containing the data models for Documentation. + * Illustrates documentation generation and formatting features. + */ +package documentation.lists.implementation; diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/lists/package-info.java b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/lists/package-info.java new file mode 100644 index 00000000000..fc9c8edd3c5 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/lists/package-info.java @@ -0,0 +1,5 @@ +/** + * Package containing the data models for Documentation. + * Illustrates documentation generation and formatting features. + */ +package documentation.lists; diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/package-info.java b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/package-info.java new file mode 100644 index 00000000000..c26939e1ae5 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/documentation/package-info.java @@ -0,0 +1,5 @@ +/** + * Package containing the classes for Documentation. + * Illustrates documentation generation and formatting features. + */ +package documentation; diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/ArrayClient.java b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/ArrayClient.java new file mode 100644 index 00000000000..98178901867 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/ArrayClient.java @@ -0,0 +1,167 @@ +package encode.array; + +import encode.array.implementation.PropertiesImpl; +import io.clientcore.core.annotations.Metadata; +import io.clientcore.core.annotations.MetadataProperties; +import io.clientcore.core.annotations.ReturnType; +import io.clientcore.core.annotations.ServiceClient; +import io.clientcore.core.annotations.ServiceMethod; +import io.clientcore.core.http.models.HttpResponseException; +import io.clientcore.core.http.models.RequestContext; +import io.clientcore.core.http.models.Response; +import io.clientcore.core.instrumentation.Instrumentation; + +/** + * Initializes a new instance of the synchronous ArrayClient type. + */ +@ServiceClient(builder = ArrayClientBuilder.class) +public final class ArrayClient { + @Metadata(properties = { MetadataProperties.GENERATED }) + private final PropertiesImpl serviceClient; + + private final Instrumentation instrumentation; + + /** + * Initializes an instance of ArrayClient class. + * + * @param serviceClient the service client implementation. + * @param instrumentation the instrumentation instance. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + ArrayClient(PropertiesImpl serviceClient, Instrumentation instrumentation) { + this.serviceClient = serviceClient; + this.instrumentation = instrumentation; + } + + /** + * The commaDelimited operation. + * + * @param body The body parameter. + * @param requestContext The context to configure the HTTP request before HTTP client sends it. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the service returns an error. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response body along with {@link Response}. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @ServiceMethod(returns = ReturnType.SINGLE) + public Response commaDelimitedWithResponse(CommaDelimitedArrayProperty body, + RequestContext requestContext) { + return this.instrumentation.instrumentWithResponse("Encode.Array.Property.commaDelimited", requestContext, + updatedContext -> this.serviceClient.commaDelimitedWithResponse(body, updatedContext)); + } + + /** + * The commaDelimited operation. + * + * @param body The body parameter. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the service returns an error. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @ServiceMethod(returns = ReturnType.SINGLE) + public CommaDelimitedArrayProperty commaDelimited(CommaDelimitedArrayProperty body) { + return commaDelimitedWithResponse(body, RequestContext.none()).getValue(); + } + + /** + * The spaceDelimited operation. + * + * @param body The body parameter. + * @param requestContext The context to configure the HTTP request before HTTP client sends it. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the service returns an error. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response body along with {@link Response}. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @ServiceMethod(returns = ReturnType.SINGLE) + public Response spaceDelimitedWithResponse(SpaceDelimitedArrayProperty body, + RequestContext requestContext) { + return this.instrumentation.instrumentWithResponse("Encode.Array.Property.spaceDelimited", requestContext, + updatedContext -> this.serviceClient.spaceDelimitedWithResponse(body, updatedContext)); + } + + /** + * The spaceDelimited operation. + * + * @param body The body parameter. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the service returns an error. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @ServiceMethod(returns = ReturnType.SINGLE) + public SpaceDelimitedArrayProperty spaceDelimited(SpaceDelimitedArrayProperty body) { + return spaceDelimitedWithResponse(body, RequestContext.none()).getValue(); + } + + /** + * The pipeDelimited operation. + * + * @param body The body parameter. + * @param requestContext The context to configure the HTTP request before HTTP client sends it. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the service returns an error. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response body along with {@link Response}. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @ServiceMethod(returns = ReturnType.SINGLE) + public Response pipeDelimitedWithResponse(PipeDelimitedArrayProperty body, + RequestContext requestContext) { + return this.instrumentation.instrumentWithResponse("Encode.Array.Property.pipeDelimited", requestContext, + updatedContext -> this.serviceClient.pipeDelimitedWithResponse(body, updatedContext)); + } + + /** + * The pipeDelimited operation. + * + * @param body The body parameter. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the service returns an error. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @ServiceMethod(returns = ReturnType.SINGLE) + public PipeDelimitedArrayProperty pipeDelimited(PipeDelimitedArrayProperty body) { + return pipeDelimitedWithResponse(body, RequestContext.none()).getValue(); + } + + /** + * The newlineDelimited operation. + * + * @param body The body parameter. + * @param requestContext The context to configure the HTTP request before HTTP client sends it. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the service returns an error. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response body along with {@link Response}. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @ServiceMethod(returns = ReturnType.SINGLE) + public Response newlineDelimitedWithResponse(NewlineDelimitedArrayProperty body, + RequestContext requestContext) { + return this.instrumentation.instrumentWithResponse("Encode.Array.Property.newlineDelimited", requestContext, + updatedContext -> this.serviceClient.newlineDelimitedWithResponse(body, updatedContext)); + } + + /** + * The newlineDelimited operation. + * + * @param body The body parameter. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the service returns an error. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @ServiceMethod(returns = ReturnType.SINGLE) + public NewlineDelimitedArrayProperty newlineDelimited(NewlineDelimitedArrayProperty body) { + return newlineDelimitedWithResponse(body, RequestContext.none()).getValue(); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/ArrayClientBuilder.java b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/ArrayClientBuilder.java new file mode 100644 index 00000000000..7f91963354e --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/ArrayClientBuilder.java @@ -0,0 +1,235 @@ +package encode.array; + +import encode.array.implementation.ArrayClientImpl; +import io.clientcore.core.annotations.Metadata; +import io.clientcore.core.annotations.MetadataProperties; +import io.clientcore.core.annotations.ServiceClientBuilder; +import io.clientcore.core.http.client.HttpClient; +import io.clientcore.core.http.models.ProxyOptions; +import io.clientcore.core.http.pipeline.HttpInstrumentationOptions; +import io.clientcore.core.http.pipeline.HttpInstrumentationPolicy; +import io.clientcore.core.http.pipeline.HttpPipeline; +import io.clientcore.core.http.pipeline.HttpPipelineBuilder; +import io.clientcore.core.http.pipeline.HttpPipelinePolicy; +import io.clientcore.core.http.pipeline.HttpRedirectOptions; +import io.clientcore.core.http.pipeline.HttpRedirectPolicy; +import io.clientcore.core.http.pipeline.HttpRetryOptions; +import io.clientcore.core.http.pipeline.HttpRetryPolicy; +import io.clientcore.core.instrumentation.Instrumentation; +import io.clientcore.core.instrumentation.SdkInstrumentationOptions; +import io.clientcore.core.traits.ConfigurationTrait; +import io.clientcore.core.traits.EndpointTrait; +import io.clientcore.core.traits.HttpTrait; +import io.clientcore.core.traits.ProxyTrait; +import io.clientcore.core.utils.CoreUtils; +import io.clientcore.core.utils.configuration.Configuration; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * A builder for creating a new instance of the ArrayClient type. + */ +@ServiceClientBuilder(serviceClients = { ArrayClient.class }) +public final class ArrayClientBuilder implements HttpTrait, ProxyTrait, + ConfigurationTrait, EndpointTrait { + @Metadata(properties = { MetadataProperties.GENERATED }) + private static final String SDK_NAME = "name"; + + @Metadata(properties = { MetadataProperties.GENERATED }) + private static final String SDK_VERSION = "version"; + + @Metadata(properties = { MetadataProperties.GENERATED }) + private static final Map PROPERTIES = CoreUtils.getProperties("encode-array.properties"); + + @Metadata(properties = { MetadataProperties.GENERATED }) + private final List pipelinePolicies; + + /** + * Create an instance of the ArrayClientBuilder. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + public ArrayClientBuilder() { + this.pipelinePolicies = new ArrayList<>(); + } + + /* + * The HTTP client used to send the request. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + private HttpClient httpClient; + + /** + * {@inheritDoc}. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @Override + public ArrayClientBuilder httpClient(HttpClient httpClient) { + this.httpClient = httpClient; + return this; + } + + /* + * The retry options to configure retry policy for failed requests. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + private HttpRetryOptions retryOptions; + + /** + * {@inheritDoc}. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @Override + public ArrayClientBuilder httpRetryOptions(HttpRetryOptions retryOptions) { + this.retryOptions = retryOptions; + return this; + } + + /** + * {@inheritDoc}. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @Override + public ArrayClientBuilder addHttpPipelinePolicy(HttpPipelinePolicy customPolicy) { + Objects.requireNonNull(customPolicy, "'customPolicy' cannot be null."); + pipelinePolicies.add(customPolicy); + return this; + } + + /* + * The redirect options to configure redirect policy + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + private HttpRedirectOptions redirectOptions; + + /** + * {@inheritDoc}. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @Override + public ArrayClientBuilder httpRedirectOptions(HttpRedirectOptions redirectOptions) { + this.redirectOptions = redirectOptions; + return this; + } + + /* + * The instrumentation configuration for HTTP requests and responses. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + private HttpInstrumentationOptions httpInstrumentationOptions; + + /** + * {@inheritDoc}. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @Override + public ArrayClientBuilder httpInstrumentationOptions(HttpInstrumentationOptions httpInstrumentationOptions) { + this.httpInstrumentationOptions = httpInstrumentationOptions; + return this; + } + + /* + * The proxy options used during construction of the service client. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + private ProxyOptions proxyOptions; + + /** + * {@inheritDoc}. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @Override + public ArrayClientBuilder proxyOptions(ProxyOptions proxyOptions) { + this.proxyOptions = proxyOptions; + return this; + } + + /* + * The configuration store that is used during construction of the service client. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + private Configuration configuration; + + /** + * {@inheritDoc}. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @Override + public ArrayClientBuilder configuration(Configuration configuration) { + this.configuration = configuration; + return this; + } + + /* + * The service endpoint + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + private String endpoint; + + /** + * {@inheritDoc}. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @Override + public ArrayClientBuilder endpoint(String endpoint) { + this.endpoint = endpoint; + return this; + } + + /** + * Builds an instance of ArrayClientImpl with the provided parameters. + * + * @return an instance of ArrayClientImpl. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + private ArrayClientImpl buildInnerClient() { + this.validateClient(); + String localEndpoint = (endpoint != null) ? endpoint : "http://localhost:3000"; + HttpInstrumentationOptions localHttpInstrumentationOptions = this.httpInstrumentationOptions == null + ? new HttpInstrumentationOptions() + : this.httpInstrumentationOptions; + SdkInstrumentationOptions sdkInstrumentationOptions + = new SdkInstrumentationOptions(PROPERTIES.getOrDefault(SDK_NAME, "UnknownName")) + .setSdkVersion(PROPERTIES.get(SDK_VERSION)) + .setEndpoint(localEndpoint); + Instrumentation instrumentation + = Instrumentation.create(localHttpInstrumentationOptions, sdkInstrumentationOptions); + ArrayClientImpl client = new ArrayClientImpl(createHttpPipeline(), instrumentation, localEndpoint); + return client; + } + + @Metadata(properties = { MetadataProperties.GENERATED }) + private void validateClient() { + // This method is invoked from 'buildInnerClient'/'buildClient' method. + // Developer can customize this method, to validate that the necessary conditions are met for the new client. + } + + @Metadata(properties = { MetadataProperties.GENERATED }) + private HttpPipeline createHttpPipeline() { + Configuration buildConfiguration + = (configuration == null) ? Configuration.getGlobalConfiguration() : configuration; + HttpInstrumentationOptions localHttpInstrumentationOptions = this.httpInstrumentationOptions == null + ? new HttpInstrumentationOptions() + : this.httpInstrumentationOptions; + HttpPipelineBuilder httpPipelineBuilder = new HttpPipelineBuilder(); + List policies = new ArrayList<>(); + policies.add(redirectOptions == null ? new HttpRedirectPolicy() : new HttpRedirectPolicy(redirectOptions)); + policies.add(retryOptions == null ? new HttpRetryPolicy() : new HttpRetryPolicy(retryOptions)); + this.pipelinePolicies.stream().forEach(p -> policies.add(p)); + policies.add(new HttpInstrumentationPolicy(localHttpInstrumentationOptions)); + policies.forEach(httpPipelineBuilder::addPolicy); + return httpPipelineBuilder.httpClient(httpClient).build(); + } + + /** + * Builds an instance of ArrayClient class. + * + * @return an instance of ArrayClient. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + public ArrayClient buildArrayClient() { + ArrayClientImpl innerClient = buildInnerClient(); + return new ArrayClient(innerClient.getProperties(), innerClient.getInstrumentation()); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/CommaDelimitedArrayProperty.java b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/CommaDelimitedArrayProperty.java new file mode 100644 index 00000000000..76d0e3a5e47 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/CommaDelimitedArrayProperty.java @@ -0,0 +1,80 @@ +package encode.array; + +import io.clientcore.core.annotations.Metadata; +import io.clientcore.core.annotations.MetadataProperties; +import io.clientcore.core.serialization.json.JsonReader; +import io.clientcore.core.serialization.json.JsonSerializable; +import io.clientcore.core.serialization.json.JsonToken; +import io.clientcore.core.serialization.json.JsonWriter; +import java.io.IOException; +import java.util.List; + +/** + * The CommaDelimitedArrayProperty model. + */ +@Metadata(properties = { MetadataProperties.IMMUTABLE }) +public final class CommaDelimitedArrayProperty implements JsonSerializable { + /* + * The value property. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + private final List value; + + /** + * Creates an instance of CommaDelimitedArrayProperty class. + * + * @param value the value value to set. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + public CommaDelimitedArrayProperty(List value) { + this.value = value; + } + + /** + * Get the value property: The value property. + * + * @return the value value. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + public List getValue() { + return this.value; + } + + /** + * {@inheritDoc} + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + jsonWriter.writeArrayField("value", this.value, (writer, element) -> writer.writeString(element)); + return jsonWriter.writeEndObject(); + } + + /** + * Reads an instance of CommaDelimitedArrayProperty from the JsonReader. + * + * @param jsonReader The JsonReader being read. + * @return An instance of CommaDelimitedArrayProperty if the JsonReader was pointing to an instance of it, or null + * if it was pointing to JSON null. + * @throws IllegalStateException If the deserialized JSON object was missing any required properties. + * @throws IOException If an error occurs while reading the CommaDelimitedArrayProperty. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + public static CommaDelimitedArrayProperty fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject(reader -> { + List value = null; + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("value".equals(fieldName)) { + value = reader.readArray(reader1 -> reader1.getString()); + } else { + reader.skipChildren(); + } + } + return new CommaDelimitedArrayProperty(value); + }); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/NewlineDelimitedArrayProperty.java b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/NewlineDelimitedArrayProperty.java new file mode 100644 index 00000000000..9c4e02945fc --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/NewlineDelimitedArrayProperty.java @@ -0,0 +1,80 @@ +package encode.array; + +import io.clientcore.core.annotations.Metadata; +import io.clientcore.core.annotations.MetadataProperties; +import io.clientcore.core.serialization.json.JsonReader; +import io.clientcore.core.serialization.json.JsonSerializable; +import io.clientcore.core.serialization.json.JsonToken; +import io.clientcore.core.serialization.json.JsonWriter; +import java.io.IOException; +import java.util.List; + +/** + * The NewlineDelimitedArrayProperty model. + */ +@Metadata(properties = { MetadataProperties.IMMUTABLE }) +public final class NewlineDelimitedArrayProperty implements JsonSerializable { + /* + * The value property. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + private final List value; + + /** + * Creates an instance of NewlineDelimitedArrayProperty class. + * + * @param value the value value to set. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + public NewlineDelimitedArrayProperty(List value) { + this.value = value; + } + + /** + * Get the value property: The value property. + * + * @return the value value. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + public List getValue() { + return this.value; + } + + /** + * {@inheritDoc} + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + jsonWriter.writeArrayField("value", this.value, (writer, element) -> writer.writeString(element)); + return jsonWriter.writeEndObject(); + } + + /** + * Reads an instance of NewlineDelimitedArrayProperty from the JsonReader. + * + * @param jsonReader The JsonReader being read. + * @return An instance of NewlineDelimitedArrayProperty if the JsonReader was pointing to an instance of it, or null + * if it was pointing to JSON null. + * @throws IllegalStateException If the deserialized JSON object was missing any required properties. + * @throws IOException If an error occurs while reading the NewlineDelimitedArrayProperty. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + public static NewlineDelimitedArrayProperty fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject(reader -> { + List value = null; + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("value".equals(fieldName)) { + value = reader.readArray(reader1 -> reader1.getString()); + } else { + reader.skipChildren(); + } + } + return new NewlineDelimitedArrayProperty(value); + }); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/PipeDelimitedArrayProperty.java b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/PipeDelimitedArrayProperty.java new file mode 100644 index 00000000000..591c83021e5 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/PipeDelimitedArrayProperty.java @@ -0,0 +1,80 @@ +package encode.array; + +import io.clientcore.core.annotations.Metadata; +import io.clientcore.core.annotations.MetadataProperties; +import io.clientcore.core.serialization.json.JsonReader; +import io.clientcore.core.serialization.json.JsonSerializable; +import io.clientcore.core.serialization.json.JsonToken; +import io.clientcore.core.serialization.json.JsonWriter; +import java.io.IOException; +import java.util.List; + +/** + * The PipeDelimitedArrayProperty model. + */ +@Metadata(properties = { MetadataProperties.IMMUTABLE }) +public final class PipeDelimitedArrayProperty implements JsonSerializable { + /* + * The value property. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + private final List value; + + /** + * Creates an instance of PipeDelimitedArrayProperty class. + * + * @param value the value value to set. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + public PipeDelimitedArrayProperty(List value) { + this.value = value; + } + + /** + * Get the value property: The value property. + * + * @return the value value. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + public List getValue() { + return this.value; + } + + /** + * {@inheritDoc} + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + jsonWriter.writeArrayField("value", this.value, (writer, element) -> writer.writeString(element)); + return jsonWriter.writeEndObject(); + } + + /** + * Reads an instance of PipeDelimitedArrayProperty from the JsonReader. + * + * @param jsonReader The JsonReader being read. + * @return An instance of PipeDelimitedArrayProperty if the JsonReader was pointing to an instance of it, or null if + * it was pointing to JSON null. + * @throws IllegalStateException If the deserialized JSON object was missing any required properties. + * @throws IOException If an error occurs while reading the PipeDelimitedArrayProperty. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + public static PipeDelimitedArrayProperty fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject(reader -> { + List value = null; + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("value".equals(fieldName)) { + value = reader.readArray(reader1 -> reader1.getString()); + } else { + reader.skipChildren(); + } + } + return new PipeDelimitedArrayProperty(value); + }); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/SpaceDelimitedArrayProperty.java b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/SpaceDelimitedArrayProperty.java new file mode 100644 index 00000000000..5b98f94f20a --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/SpaceDelimitedArrayProperty.java @@ -0,0 +1,80 @@ +package encode.array; + +import io.clientcore.core.annotations.Metadata; +import io.clientcore.core.annotations.MetadataProperties; +import io.clientcore.core.serialization.json.JsonReader; +import io.clientcore.core.serialization.json.JsonSerializable; +import io.clientcore.core.serialization.json.JsonToken; +import io.clientcore.core.serialization.json.JsonWriter; +import java.io.IOException; +import java.util.List; + +/** + * The SpaceDelimitedArrayProperty model. + */ +@Metadata(properties = { MetadataProperties.IMMUTABLE }) +public final class SpaceDelimitedArrayProperty implements JsonSerializable { + /* + * The value property. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + private final List value; + + /** + * Creates an instance of SpaceDelimitedArrayProperty class. + * + * @param value the value value to set. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + public SpaceDelimitedArrayProperty(List value) { + this.value = value; + } + + /** + * Get the value property: The value property. + * + * @return the value value. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + public List getValue() { + return this.value; + } + + /** + * {@inheritDoc} + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + jsonWriter.writeArrayField("value", this.value, (writer, element) -> writer.writeString(element)); + return jsonWriter.writeEndObject(); + } + + /** + * Reads an instance of SpaceDelimitedArrayProperty from the JsonReader. + * + * @param jsonReader The JsonReader being read. + * @return An instance of SpaceDelimitedArrayProperty if the JsonReader was pointing to an instance of it, or null + * if it was pointing to JSON null. + * @throws IllegalStateException If the deserialized JSON object was missing any required properties. + * @throws IOException If an error occurs while reading the SpaceDelimitedArrayProperty. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + public static SpaceDelimitedArrayProperty fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject(reader -> { + List value = null; + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("value".equals(fieldName)) { + value = reader.readArray(reader1 -> reader1.getString()); + } else { + reader.skipChildren(); + } + } + return new SpaceDelimitedArrayProperty(value); + }); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/implementation/ArrayClientImpl.java b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/implementation/ArrayClientImpl.java new file mode 100644 index 00000000000..3594e1a6fd6 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/implementation/ArrayClientImpl.java @@ -0,0 +1,79 @@ +package encode.array.implementation; + +import io.clientcore.core.http.pipeline.HttpPipeline; +import io.clientcore.core.instrumentation.Instrumentation; + +/** + * Initializes a new instance of the ArrayClient type. + */ +public final class ArrayClientImpl { + /** + * Service host. + */ + private final String endpoint; + + /** + * Gets Service host. + * + * @return the endpoint value. + */ + public String getEndpoint() { + return this.endpoint; + } + + /** + * The HTTP pipeline to send requests through. + */ + private final HttpPipeline httpPipeline; + + /** + * Gets The HTTP pipeline to send requests through. + * + * @return the httpPipeline value. + */ + public HttpPipeline getHttpPipeline() { + return this.httpPipeline; + } + + /** + * The instance of instrumentation to report telemetry. + */ + private final Instrumentation instrumentation; + + /** + * Gets The instance of instrumentation to report telemetry. + * + * @return the instrumentation value. + */ + public Instrumentation getInstrumentation() { + return this.instrumentation; + } + + /** + * The PropertiesImpl object to access its operations. + */ + private final PropertiesImpl properties; + + /** + * Gets the PropertiesImpl object to access its operations. + * + * @return the PropertiesImpl object. + */ + public PropertiesImpl getProperties() { + return this.properties; + } + + /** + * Initializes an instance of ArrayClient client. + * + * @param httpPipeline The HTTP pipeline to send requests through. + * @param instrumentation The instance of instrumentation to report telemetry. + * @param endpoint Service host. + */ + public ArrayClientImpl(HttpPipeline httpPipeline, Instrumentation instrumentation, String endpoint) { + this.httpPipeline = httpPipeline; + this.instrumentation = instrumentation; + this.endpoint = endpoint; + this.properties = new PropertiesImpl(this); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/implementation/PropertiesImpl.java b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/implementation/PropertiesImpl.java new file mode 100644 index 00000000000..c87416a9952 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/implementation/PropertiesImpl.java @@ -0,0 +1,190 @@ +package encode.array.implementation; + +import encode.array.CommaDelimitedArrayProperty; +import encode.array.NewlineDelimitedArrayProperty; +import encode.array.PipeDelimitedArrayProperty; +import encode.array.SpaceDelimitedArrayProperty; +import io.clientcore.core.annotations.ReturnType; +import io.clientcore.core.annotations.ServiceInterface; +import io.clientcore.core.annotations.ServiceMethod; +import io.clientcore.core.http.annotations.BodyParam; +import io.clientcore.core.http.annotations.HeaderParam; +import io.clientcore.core.http.annotations.HostParam; +import io.clientcore.core.http.annotations.HttpRequestInformation; +import io.clientcore.core.http.annotations.UnexpectedResponseExceptionDetail; +import io.clientcore.core.http.models.HttpMethod; +import io.clientcore.core.http.models.HttpResponseException; +import io.clientcore.core.http.models.RequestContext; +import io.clientcore.core.http.models.Response; +import io.clientcore.core.http.pipeline.HttpPipeline; +import io.clientcore.core.instrumentation.Instrumentation; +import java.lang.reflect.InvocationTargetException; + +/** + * An instance of this class provides access to all the operations defined in Properties. + */ +public final class PropertiesImpl { + /** + * The proxy service used to perform REST calls. + */ + private final PropertiesService service; + + /** + * The service client containing this operation class. + */ + private final ArrayClientImpl client; + + /** + * The instance of instrumentation to report telemetry. + */ + private final Instrumentation instrumentation; + + /** + * Initializes an instance of PropertiesImpl. + * + * @param client the instance of the service client containing this operation class. + */ + PropertiesImpl(ArrayClientImpl client) { + this.service = PropertiesService.getNewInstance(client.getHttpPipeline()); + this.client = client; + this.instrumentation = client.getInstrumentation(); + } + + /** + * The interface defining all the services for ArrayClientProperties to be used by the proxy service to perform REST + * calls. + */ + @ServiceInterface(name = "ArrayClientProperties", host = "{endpoint}") + public interface PropertiesService { + static PropertiesService getNewInstance(HttpPipeline pipeline) { + try { + Class clazz = Class.forName("encode.array.implementation.PropertiesServiceImpl"); + return (PropertiesService) clazz.getMethod("getNewInstance", HttpPipeline.class).invoke(null, pipeline); + } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException + | InvocationTargetException e) { + throw new RuntimeException(e); + } + + } + + @HttpRequestInformation( + method = HttpMethod.POST, + path = "/encode/array/property/comma-delimited", + expectedStatusCodes = { 200 }) + @UnexpectedResponseExceptionDetail + Response commaDelimited(@HostParam("endpoint") String endpoint, + @HeaderParam("Content-Type") String contentType, @HeaderParam("Accept") String accept, + @BodyParam("application/json") CommaDelimitedArrayProperty body, RequestContext requestContext); + + @HttpRequestInformation( + method = HttpMethod.POST, + path = "/encode/array/property/space-delimited", + expectedStatusCodes = { 200 }) + @UnexpectedResponseExceptionDetail + Response spaceDelimited(@HostParam("endpoint") String endpoint, + @HeaderParam("Content-Type") String contentType, @HeaderParam("Accept") String accept, + @BodyParam("application/json") SpaceDelimitedArrayProperty body, RequestContext requestContext); + + @HttpRequestInformation( + method = HttpMethod.POST, + path = "/encode/array/property/pipe-delimited", + expectedStatusCodes = { 200 }) + @UnexpectedResponseExceptionDetail + Response pipeDelimited(@HostParam("endpoint") String endpoint, + @HeaderParam("Content-Type") String contentType, @HeaderParam("Accept") String accept, + @BodyParam("application/json") PipeDelimitedArrayProperty body, RequestContext requestContext); + + @HttpRequestInformation( + method = HttpMethod.POST, + path = "/encode/array/property/newline-delimited", + expectedStatusCodes = { 200 }) + @UnexpectedResponseExceptionDetail + Response newlineDelimited(@HostParam("endpoint") String endpoint, + @HeaderParam("Content-Type") String contentType, @HeaderParam("Accept") String accept, + @BodyParam("application/json") NewlineDelimitedArrayProperty body, RequestContext requestContext); + } + + /** + * The commaDelimited operation. + * + * @param body The body parameter. + * @param requestContext The context to configure the HTTP request before HTTP client sends it. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the service returns an error. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response body along with {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response commaDelimitedWithResponse(CommaDelimitedArrayProperty body, + RequestContext requestContext) { + return this.instrumentation.instrumentWithResponse("Encode.Array.Property.commaDelimited", requestContext, + updatedContext -> { + final String contentType = "application/json"; + final String accept = "application/json"; + return service.commaDelimited(this.client.getEndpoint(), contentType, accept, body, updatedContext); + }); + } + + /** + * The spaceDelimited operation. + * + * @param body The body parameter. + * @param requestContext The context to configure the HTTP request before HTTP client sends it. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the service returns an error. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response body along with {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response spaceDelimitedWithResponse(SpaceDelimitedArrayProperty body, + RequestContext requestContext) { + return this.instrumentation.instrumentWithResponse("Encode.Array.Property.spaceDelimited", requestContext, + updatedContext -> { + final String contentType = "application/json"; + final String accept = "application/json"; + return service.spaceDelimited(this.client.getEndpoint(), contentType, accept, body, updatedContext); + }); + } + + /** + * The pipeDelimited operation. + * + * @param body The body parameter. + * @param requestContext The context to configure the HTTP request before HTTP client sends it. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the service returns an error. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response body along with {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response pipeDelimitedWithResponse(PipeDelimitedArrayProperty body, + RequestContext requestContext) { + return this.instrumentation.instrumentWithResponse("Encode.Array.Property.pipeDelimited", requestContext, + updatedContext -> { + final String contentType = "application/json"; + final String accept = "application/json"; + return service.pipeDelimited(this.client.getEndpoint(), contentType, accept, body, updatedContext); + }); + } + + /** + * The newlineDelimited operation. + * + * @param body The body parameter. + * @param requestContext The context to configure the HTTP request before HTTP client sends it. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the service returns an error. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response body along with {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response newlineDelimitedWithResponse(NewlineDelimitedArrayProperty body, + RequestContext requestContext) { + return this.instrumentation.instrumentWithResponse("Encode.Array.Property.newlineDelimited", requestContext, + updatedContext -> { + final String contentType = "application/json"; + final String accept = "application/json"; + return service.newlineDelimited(this.client.getEndpoint(), contentType, accept, body, updatedContext); + }); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/implementation/package-info.java b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/implementation/package-info.java new file mode 100644 index 00000000000..3ef73b3879e --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/implementation/package-info.java @@ -0,0 +1,5 @@ +/** + * Package containing the implementations for Array. + * Test for encode decorator on array. + */ +package encode.array.implementation; diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/package-info.java b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/package-info.java new file mode 100644 index 00000000000..3d3dfef05bb --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/encode/array/package-info.java @@ -0,0 +1,5 @@ +/** + * Package containing the classes for Array. + * Test for encode decorator on array. + */ +package encode.array; diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/specialwords/ModelPropertiesClient.java b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/specialwords/ModelPropertiesClient.java index 31fd6614a82..d52c323c8f6 100644 --- a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/specialwords/ModelPropertiesClient.java +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/specialwords/ModelPropertiesClient.java @@ -10,6 +10,7 @@ import io.clientcore.core.http.models.Response; import io.clientcore.core.instrumentation.Instrumentation; import specialwords.implementation.ModelPropertiesImpl; +import specialwords.modelproperties.DictMethods; import specialwords.modelproperties.SameAsModel; /** @@ -64,4 +65,35 @@ public Response sameAsModelWithResponse(SameAsModel body, RequestContext r public void sameAsModel(SameAsModel body) { sameAsModelWithResponse(body, RequestContext.none()); } + + /** + * The dictMethods operation. + * + * @param body The body parameter. + * @param requestContext The context to configure the HTTP request before HTTP client sends it. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the service returns an error. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the {@link Response}. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @ServiceMethod(returns = ReturnType.SINGLE) + public Response dictMethodsWithResponse(DictMethods body, RequestContext requestContext) { + return this.instrumentation.instrumentWithResponse("SpecialWords.ModelProperties.dictMethods", requestContext, + updatedContext -> this.serviceClient.dictMethodsWithResponse(body, updatedContext)); + } + + /** + * The dictMethods operation. + * + * @param body The body parameter. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the service returns an error. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @ServiceMethod(returns = ReturnType.SINGLE) + public void dictMethods(DictMethods body) { + dictMethodsWithResponse(body, RequestContext.none()); + } } diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/specialwords/implementation/ModelPropertiesImpl.java b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/specialwords/implementation/ModelPropertiesImpl.java index 07dfadaa958..b7c55e030d1 100644 --- a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/specialwords/implementation/ModelPropertiesImpl.java +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/specialwords/implementation/ModelPropertiesImpl.java @@ -15,6 +15,7 @@ import io.clientcore.core.http.pipeline.HttpPipeline; import io.clientcore.core.instrumentation.Instrumentation; import java.lang.reflect.InvocationTargetException; +import specialwords.modelproperties.DictMethods; import specialwords.modelproperties.SameAsModel; /** @@ -73,6 +74,15 @@ static ModelPropertiesService getNewInstance(HttpPipeline pipeline) { Response sameAsModel(@HostParam("endpoint") String endpoint, @HeaderParam("Content-Type") String contentType, @BodyParam("application/json") SameAsModel body, RequestContext requestContext); + + @HttpRequestInformation( + method = HttpMethod.POST, + path = "/special-words/model-properties/dict-methods", + expectedStatusCodes = { 204 }) + @UnexpectedResponseExceptionDetail + Response dictMethods(@HostParam("endpoint") String endpoint, + @HeaderParam("Content-Type") String contentType, @BodyParam("application/json") DictMethods body, + RequestContext requestContext); } /** @@ -93,4 +103,23 @@ public Response sameAsModelWithResponse(SameAsModel body, RequestContext r return service.sameAsModel(this.client.getEndpoint(), contentType, body, updatedContext); }); } + + /** + * The dictMethods operation. + * + * @param body The body parameter. + * @param requestContext The context to configure the HTTP request before HTTP client sends it. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the service returns an error. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response dictMethodsWithResponse(DictMethods body, RequestContext requestContext) { + return this.instrumentation.instrumentWithResponse("SpecialWords.ModelProperties.dictMethods", requestContext, + updatedContext -> { + final String contentType = "application/json"; + return service.dictMethods(this.client.getEndpoint(), contentType, body, updatedContext); + }); + } } diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/specialwords/modelproperties/DictMethods.java b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/specialwords/modelproperties/DictMethods.java new file mode 100644 index 00000000000..3808e98b525 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/java/specialwords/modelproperties/DictMethods.java @@ -0,0 +1,278 @@ +package specialwords.modelproperties; + +import io.clientcore.core.annotations.Metadata; +import io.clientcore.core.annotations.MetadataProperties; +import io.clientcore.core.serialization.json.JsonReader; +import io.clientcore.core.serialization.json.JsonSerializable; +import io.clientcore.core.serialization.json.JsonToken; +import io.clientcore.core.serialization.json.JsonWriter; +import java.io.IOException; + +/** + * The DictMethods model. + */ +@Metadata(properties = { MetadataProperties.IMMUTABLE }) +public final class DictMethods implements JsonSerializable { + /* + * The keys property. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + private final String keys; + + /* + * The items property. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + private final String items; + + /* + * The values property. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + private final String values; + + /* + * The popitem property. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + private final String popitem; + + /* + * The clear property. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + private final String clear; + + /* + * The update property. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + private final String update; + + /* + * The setdefault property. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + private final String setdefault; + + /* + * The pop property. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + private final String pop; + + /* + * The get property. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + private final String get; + + /* + * The copy property. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + private final String copy; + + /** + * Creates an instance of DictMethods class. + * + * @param keys the keys value to set. + * @param items the items value to set. + * @param values the values value to set. + * @param popitem the popitem value to set. + * @param clear the clear value to set. + * @param update the update value to set. + * @param setdefault the setdefault value to set. + * @param pop the pop value to set. + * @param get the get value to set. + * @param copy the copy value to set. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + public DictMethods(String keys, String items, String values, String popitem, String clear, String update, + String setdefault, String pop, String get, String copy) { + this.keys = keys; + this.items = items; + this.values = values; + this.popitem = popitem; + this.clear = clear; + this.update = update; + this.setdefault = setdefault; + this.pop = pop; + this.get = get; + this.copy = copy; + } + + /** + * Get the keys property: The keys property. + * + * @return the keys value. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + public String getKeys() { + return this.keys; + } + + /** + * Get the items property: The items property. + * + * @return the items value. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + public String getItems() { + return this.items; + } + + /** + * Get the values property: The values property. + * + * @return the values value. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + public String getValues() { + return this.values; + } + + /** + * Get the popitem property: The popitem property. + * + * @return the popitem value. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + public String getPopitem() { + return this.popitem; + } + + /** + * Get the clear property: The clear property. + * + * @return the clear value. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + public String getClear() { + return this.clear; + } + + /** + * Get the update property: The update property. + * + * @return the update value. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + public String getUpdate() { + return this.update; + } + + /** + * Get the setdefault property: The setdefault property. + * + * @return the setdefault value. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + public String getSetdefault() { + return this.setdefault; + } + + /** + * Get the pop property: The pop property. + * + * @return the pop value. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + public String getPop() { + return this.pop; + } + + /** + * Get the get property: The get property. + * + * @return the get value. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + public String getGet() { + return this.get; + } + + /** + * Get the copy property: The copy property. + * + * @return the copy value. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + public String getCopy() { + return this.copy; + } + + /** + * {@inheritDoc} + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + jsonWriter.writeStringField("keys", this.keys); + jsonWriter.writeStringField("items", this.items); + jsonWriter.writeStringField("values", this.values); + jsonWriter.writeStringField("popitem", this.popitem); + jsonWriter.writeStringField("clear", this.clear); + jsonWriter.writeStringField("update", this.update); + jsonWriter.writeStringField("setdefault", this.setdefault); + jsonWriter.writeStringField("pop", this.pop); + jsonWriter.writeStringField("get", this.get); + jsonWriter.writeStringField("copy", this.copy); + return jsonWriter.writeEndObject(); + } + + /** + * Reads an instance of DictMethods from the JsonReader. + * + * @param jsonReader The JsonReader being read. + * @return An instance of DictMethods if the JsonReader was pointing to an instance of it, or null if it was + * pointing to JSON null. + * @throws IllegalStateException If the deserialized JSON object was missing any required properties. + * @throws IOException If an error occurs while reading the DictMethods. + */ + @Metadata(properties = { MetadataProperties.GENERATED }) + public static DictMethods fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject(reader -> { + String keys = null; + String items = null; + String values = null; + String popitem = null; + String clear = null; + String update = null; + String setdefault = null; + String pop = null; + String get = null; + String copy = null; + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("keys".equals(fieldName)) { + keys = reader.getString(); + } else if ("items".equals(fieldName)) { + items = reader.getString(); + } else if ("values".equals(fieldName)) { + values = reader.getString(); + } else if ("popitem".equals(fieldName)) { + popitem = reader.getString(); + } else if ("clear".equals(fieldName)) { + clear = reader.getString(); + } else if ("update".equals(fieldName)) { + update = reader.getString(); + } else if ("setdefault".equals(fieldName)) { + setdefault = reader.getString(); + } else if ("pop".equals(fieldName)) { + pop = reader.getString(); + } else if ("get".equals(fieldName)) { + get = reader.getString(); + } else if ("copy".equals(fieldName)) { + copy = reader.getString(); + } else { + reader.skipChildren(); + } + } + return new DictMethods(keys, items, values, popitem, clear, update, setdefault, pop, get, copy); + }); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/resources/META-INF/documentation_apiview_properties.json b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/resources/META-INF/documentation_apiview_properties.json new file mode 100644 index 00000000000..4e7018f5979 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/resources/META-INF/documentation_apiview_properties.json @@ -0,0 +1,11 @@ +{ + "flavor": "generic", + "CrossLanguageDefinitionId": { + "documentation.DocumentationClientBuilder": "Documentation", + "documentation.ListsClient": "Documentation.Lists", + "documentation.TextFormattingClient": "Documentation.TextFormatting", + "documentation.lists.BulletPointsEnum": "Documentation.Lists.BulletPointsEnum", + "documentation.lists.BulletPointsModel": "Documentation.Lists.BulletPointsModel", + "documentation.lists.implementation.BulletPointsModelRequest": "Documentation.Lists.bulletPointsModel.Request.anonymous" + } +} diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/resources/META-INF/documentation_metadata.json b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/resources/META-INF/documentation_metadata.json new file mode 100644 index 00000000000..e80af789b53 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/resources/META-INF/documentation_metadata.json @@ -0,0 +1 @@ +{"flavor":"generic","crossLanguageDefinitions":{"documentation.DocumentationClientBuilder":"Documentation","documentation.ListsClient":"Documentation.Lists","documentation.TextFormattingClient":"Documentation.TextFormatting","documentation.lists.BulletPointsEnum":"Documentation.Lists.BulletPointsEnum","documentation.lists.BulletPointsModel":"Documentation.Lists.BulletPointsModel","documentation.lists.implementation.BulletPointsModelRequest":"Documentation.Lists.bulletPointsModel.Request.anonymous"},"generatedFiles":["src/main/java/documentation/DocumentationClientBuilder.java","src/main/java/documentation/ListsClient.java","src/main/java/documentation/TextFormattingClient.java","src/main/java/documentation/implementation/DocumentationClientImpl.java","src/main/java/documentation/implementation/ListsImpl.java","src/main/java/documentation/implementation/TextFormattingsImpl.java","src/main/java/documentation/implementation/package-info.java","src/main/java/documentation/lists/BulletPointsEnum.java","src/main/java/documentation/lists/BulletPointsModel.java","src/main/java/documentation/lists/implementation/BulletPointsModelRequest.java","src/main/java/documentation/lists/implementation/package-info.java","src/main/java/documentation/lists/package-info.java","src/main/java/documentation/package-info.java","src/main/java/module-info.java"]} \ No newline at end of file diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/resources/META-INF/encode-array_apiview_properties.json b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/resources/META-INF/encode-array_apiview_properties.json new file mode 100644 index 00000000000..196e528b2b2 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/resources/META-INF/encode-array_apiview_properties.json @@ -0,0 +1,11 @@ +{ + "flavor": "generic", + "CrossLanguageDefinitionId": { + "encode.array.ArrayClient": "Encode.Array.Property", + "encode.array.ArrayClientBuilder": "Encode.Array", + "encode.array.CommaDelimitedArrayProperty": "Encode.Array.CommaDelimitedArrayProperty", + "encode.array.NewlineDelimitedArrayProperty": "Encode.Array.NewlineDelimitedArrayProperty", + "encode.array.PipeDelimitedArrayProperty": "Encode.Array.PipeDelimitedArrayProperty", + "encode.array.SpaceDelimitedArrayProperty": "Encode.Array.SpaceDelimitedArrayProperty" + } +} diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/resources/META-INF/encode-array_metadata.json b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/resources/META-INF/encode-array_metadata.json new file mode 100644 index 00000000000..7ded8c90498 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/resources/META-INF/encode-array_metadata.json @@ -0,0 +1 @@ +{"flavor":"generic","crossLanguageDefinitions":{"encode.array.ArrayClient":"Encode.Array.Property","encode.array.ArrayClientBuilder":"Encode.Array","encode.array.CommaDelimitedArrayProperty":"Encode.Array.CommaDelimitedArrayProperty","encode.array.NewlineDelimitedArrayProperty":"Encode.Array.NewlineDelimitedArrayProperty","encode.array.PipeDelimitedArrayProperty":"Encode.Array.PipeDelimitedArrayProperty","encode.array.SpaceDelimitedArrayProperty":"Encode.Array.SpaceDelimitedArrayProperty"},"generatedFiles":["src/main/java/encode/array/ArrayClient.java","src/main/java/encode/array/ArrayClientBuilder.java","src/main/java/encode/array/CommaDelimitedArrayProperty.java","src/main/java/encode/array/NewlineDelimitedArrayProperty.java","src/main/java/encode/array/PipeDelimitedArrayProperty.java","src/main/java/encode/array/SpaceDelimitedArrayProperty.java","src/main/java/encode/array/implementation/ArrayClientImpl.java","src/main/java/encode/array/implementation/PropertiesImpl.java","src/main/java/encode/array/implementation/package-info.java","src/main/java/encode/array/package-info.java","src/main/java/module-info.java"]} \ No newline at end of file diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/resources/META-INF/specialwords_apiview_properties.json b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/resources/META-INF/specialwords_apiview_properties.json index 5fcefb54893..d5c92b3c161 100644 --- a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/resources/META-INF/specialwords_apiview_properties.json +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/resources/META-INF/specialwords_apiview_properties.json @@ -6,6 +6,7 @@ "specialwords.OperationsClient": "SpecialWords.Operations", "specialwords.ParametersClient": "SpecialWords.Parameters", "specialwords.SpecialWordsClientBuilder": "SpecialWords", + "specialwords.modelproperties.DictMethods": "SpecialWords.ModelProperties.DictMethods", "specialwords.modelproperties.SameAsModel": "SpecialWords.ModelProperties.SameAsModel", "specialwords.models.And": "SpecialWords.Models.and", "specialwords.models.As": "SpecialWords.Models.as", diff --git a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/resources/META-INF/specialwords_metadata.json b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/resources/META-INF/specialwords_metadata.json index 4c7a8d845e7..5378276e7d3 100644 --- a/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/resources/META-INF/specialwords_metadata.json +++ b/packages/http-client-java/generator/http-client-generator-clientcore-test/src/main/resources/META-INF/specialwords_metadata.json @@ -1 +1 @@ -{"flavor":"generic","crossLanguageDefinitions":{"specialwords.ModelPropertiesClient":"SpecialWords.ModelProperties","specialwords.ModelsClient":"SpecialWords.Models","specialwords.OperationsClient":"SpecialWords.Operations","specialwords.ParametersClient":"SpecialWords.Parameters","specialwords.SpecialWordsClientBuilder":"SpecialWords","specialwords.modelproperties.SameAsModel":"SpecialWords.ModelProperties.SameAsModel","specialwords.models.And":"SpecialWords.Models.and","specialwords.models.As":"SpecialWords.Models.as","specialwords.models.Assert":"SpecialWords.Models.assert","specialwords.models.Async":"SpecialWords.Models.async","specialwords.models.Await":"SpecialWords.Models.await","specialwords.models.Break":"SpecialWords.Models.break","specialwords.models.ClassModel":"SpecialWords.Models.class","specialwords.models.Constructor":"SpecialWords.Models.constructor","specialwords.models.Continue":"SpecialWords.Models.continue","specialwords.models.Def":"SpecialWords.Models.def","specialwords.models.Del":"SpecialWords.Models.del","specialwords.models.Elif":"SpecialWords.Models.elif","specialwords.models.Else":"SpecialWords.Models.else","specialwords.models.Except":"SpecialWords.Models.except","specialwords.models.Exec":"SpecialWords.Models.exec","specialwords.models.Finally":"SpecialWords.Models.finally","specialwords.models.For":"SpecialWords.Models.for","specialwords.models.From":"SpecialWords.Models.from","specialwords.models.Global":"SpecialWords.Models.global","specialwords.models.If":"SpecialWords.Models.if","specialwords.models.Import":"SpecialWords.Models.import","specialwords.models.In":"SpecialWords.Models.in","specialwords.models.Is":"SpecialWords.Models.is","specialwords.models.Lambda":"SpecialWords.Models.lambda","specialwords.models.Not":"SpecialWords.Models.not","specialwords.models.Or":"SpecialWords.Models.or","specialwords.models.Pass":"SpecialWords.Models.pass","specialwords.models.Raise":"SpecialWords.Models.raise","specialwords.models.Return":"SpecialWords.Models.return","specialwords.models.Try":"SpecialWords.Models.try","specialwords.models.While":"SpecialWords.Models.while","specialwords.models.With":"SpecialWords.Models.with","specialwords.models.Yield":"SpecialWords.Models.yield"},"generatedFiles":["src/main/java/module-info.java","src/main/java/specialwords/ModelPropertiesClient.java","src/main/java/specialwords/ModelsClient.java","src/main/java/specialwords/OperationsClient.java","src/main/java/specialwords/ParametersClient.java","src/main/java/specialwords/SpecialWordsClientBuilder.java","src/main/java/specialwords/implementation/ModelPropertiesImpl.java","src/main/java/specialwords/implementation/ModelsImpl.java","src/main/java/specialwords/implementation/OperationsImpl.java","src/main/java/specialwords/implementation/ParametersImpl.java","src/main/java/specialwords/implementation/SpecialWordsClientImpl.java","src/main/java/specialwords/implementation/package-info.java","src/main/java/specialwords/modelproperties/SameAsModel.java","src/main/java/specialwords/modelproperties/package-info.java","src/main/java/specialwords/models/And.java","src/main/java/specialwords/models/As.java","src/main/java/specialwords/models/Assert.java","src/main/java/specialwords/models/Async.java","src/main/java/specialwords/models/Await.java","src/main/java/specialwords/models/Break.java","src/main/java/specialwords/models/ClassModel.java","src/main/java/specialwords/models/Constructor.java","src/main/java/specialwords/models/Continue.java","src/main/java/specialwords/models/Def.java","src/main/java/specialwords/models/Del.java","src/main/java/specialwords/models/Elif.java","src/main/java/specialwords/models/Else.java","src/main/java/specialwords/models/Except.java","src/main/java/specialwords/models/Exec.java","src/main/java/specialwords/models/Finally.java","src/main/java/specialwords/models/For.java","src/main/java/specialwords/models/From.java","src/main/java/specialwords/models/Global.java","src/main/java/specialwords/models/If.java","src/main/java/specialwords/models/Import.java","src/main/java/specialwords/models/In.java","src/main/java/specialwords/models/Is.java","src/main/java/specialwords/models/Lambda.java","src/main/java/specialwords/models/Not.java","src/main/java/specialwords/models/Or.java","src/main/java/specialwords/models/Pass.java","src/main/java/specialwords/models/Raise.java","src/main/java/specialwords/models/Return.java","src/main/java/specialwords/models/Try.java","src/main/java/specialwords/models/While.java","src/main/java/specialwords/models/With.java","src/main/java/specialwords/models/Yield.java","src/main/java/specialwords/models/package-info.java","src/main/java/specialwords/package-info.java"]} \ No newline at end of file +{"flavor":"generic","crossLanguageDefinitions":{"specialwords.ModelPropertiesClient":"SpecialWords.ModelProperties","specialwords.ModelsClient":"SpecialWords.Models","specialwords.OperationsClient":"SpecialWords.Operations","specialwords.ParametersClient":"SpecialWords.Parameters","specialwords.SpecialWordsClientBuilder":"SpecialWords","specialwords.modelproperties.DictMethods":"SpecialWords.ModelProperties.DictMethods","specialwords.modelproperties.SameAsModel":"SpecialWords.ModelProperties.SameAsModel","specialwords.models.And":"SpecialWords.Models.and","specialwords.models.As":"SpecialWords.Models.as","specialwords.models.Assert":"SpecialWords.Models.assert","specialwords.models.Async":"SpecialWords.Models.async","specialwords.models.Await":"SpecialWords.Models.await","specialwords.models.Break":"SpecialWords.Models.break","specialwords.models.ClassModel":"SpecialWords.Models.class","specialwords.models.Constructor":"SpecialWords.Models.constructor","specialwords.models.Continue":"SpecialWords.Models.continue","specialwords.models.Def":"SpecialWords.Models.def","specialwords.models.Del":"SpecialWords.Models.del","specialwords.models.Elif":"SpecialWords.Models.elif","specialwords.models.Else":"SpecialWords.Models.else","specialwords.models.Except":"SpecialWords.Models.except","specialwords.models.Exec":"SpecialWords.Models.exec","specialwords.models.Finally":"SpecialWords.Models.finally","specialwords.models.For":"SpecialWords.Models.for","specialwords.models.From":"SpecialWords.Models.from","specialwords.models.Global":"SpecialWords.Models.global","specialwords.models.If":"SpecialWords.Models.if","specialwords.models.Import":"SpecialWords.Models.import","specialwords.models.In":"SpecialWords.Models.in","specialwords.models.Is":"SpecialWords.Models.is","specialwords.models.Lambda":"SpecialWords.Models.lambda","specialwords.models.Not":"SpecialWords.Models.not","specialwords.models.Or":"SpecialWords.Models.or","specialwords.models.Pass":"SpecialWords.Models.pass","specialwords.models.Raise":"SpecialWords.Models.raise","specialwords.models.Return":"SpecialWords.Models.return","specialwords.models.Try":"SpecialWords.Models.try","specialwords.models.While":"SpecialWords.Models.while","specialwords.models.With":"SpecialWords.Models.with","specialwords.models.Yield":"SpecialWords.Models.yield"},"generatedFiles":["src/main/java/module-info.java","src/main/java/specialwords/ModelPropertiesClient.java","src/main/java/specialwords/ModelsClient.java","src/main/java/specialwords/OperationsClient.java","src/main/java/specialwords/ParametersClient.java","src/main/java/specialwords/SpecialWordsClientBuilder.java","src/main/java/specialwords/implementation/ModelPropertiesImpl.java","src/main/java/specialwords/implementation/ModelsImpl.java","src/main/java/specialwords/implementation/OperationsImpl.java","src/main/java/specialwords/implementation/ParametersImpl.java","src/main/java/specialwords/implementation/SpecialWordsClientImpl.java","src/main/java/specialwords/implementation/package-info.java","src/main/java/specialwords/modelproperties/DictMethods.java","src/main/java/specialwords/modelproperties/SameAsModel.java","src/main/java/specialwords/modelproperties/package-info.java","src/main/java/specialwords/models/And.java","src/main/java/specialwords/models/As.java","src/main/java/specialwords/models/Assert.java","src/main/java/specialwords/models/Async.java","src/main/java/specialwords/models/Await.java","src/main/java/specialwords/models/Break.java","src/main/java/specialwords/models/ClassModel.java","src/main/java/specialwords/models/Constructor.java","src/main/java/specialwords/models/Continue.java","src/main/java/specialwords/models/Def.java","src/main/java/specialwords/models/Del.java","src/main/java/specialwords/models/Elif.java","src/main/java/specialwords/models/Else.java","src/main/java/specialwords/models/Except.java","src/main/java/specialwords/models/Exec.java","src/main/java/specialwords/models/Finally.java","src/main/java/specialwords/models/For.java","src/main/java/specialwords/models/From.java","src/main/java/specialwords/models/Global.java","src/main/java/specialwords/models/If.java","src/main/java/specialwords/models/Import.java","src/main/java/specialwords/models/In.java","src/main/java/specialwords/models/Is.java","src/main/java/specialwords/models/Lambda.java","src/main/java/specialwords/models/Not.java","src/main/java/specialwords/models/Or.java","src/main/java/specialwords/models/Pass.java","src/main/java/specialwords/models/Raise.java","src/main/java/specialwords/models/Return.java","src/main/java/specialwords/models/Try.java","src/main/java/specialwords/models/While.java","src/main/java/specialwords/models/With.java","src/main/java/specialwords/models/Yield.java","src/main/java/specialwords/models/package-info.java","src/main/java/specialwords/package-info.java"]} \ No newline at end of file diff --git a/packages/http-client-java/generator/http-client-generator-test/package.json b/packages/http-client-java/generator/http-client-generator-test/package.json index 9b649a5d783..1285ccb6134 100644 --- a/packages/http-client-java/generator/http-client-generator-test/package.json +++ b/packages/http-client-java/generator/http-client-generator-test/package.json @@ -12,27 +12,27 @@ "spector-stop": "tsp-spector server stop" }, "dependencies": { - "@typespec/spector": "0.1.0-alpha.20", - "@typespec/spec-api": "0.1.0-alpha.10", - "@typespec/http-specs": "0.1.0-alpha.28", - "@azure-tools/azure-http-specs": "0.1.0-alpha.32", - "@typespec/http-client-java": "file:../../typespec-http-client-java-0.6.0.tgz", + "@typespec/spector": "0.1.0-alpha.21", + "@typespec/spec-api": "0.1.0-alpha.11", + "@typespec/http-specs": "0.1.0-alpha.29", + "@azure-tools/azure-http-specs": "0.1.0-alpha.33", + "@typespec/http-client-java": "file:../../typespec-http-client-java-0.6.1.tgz", "@typespec/http-client-java-tests": "file:" }, "overrides": { - "@typespec/compiler": "1.6.0", - "@typespec/http": "1.6.0", - "@typespec/rest": "0.76.0", - "@typespec/versioning": "0.76.0", - "@typespec/openapi": "1.6.0", - "@typespec/xml": "0.76.0", - "@typespec/events": "0.76.0", - "@typespec/sse": "0.76.0", - "@typespec/streams": "0.76.0", - "@azure-tools/typespec-azure-core": "0.62.0", - "@azure-tools/typespec-client-generator-core": "0.62.0", - "@azure-tools/typespec-azure-resource-manager": "0.62.1", - "@azure-tools/typespec-autorest": "0.62.0" + "@typespec/compiler": "1.7.0", + "@typespec/http": "1.7.0", + "@typespec/rest": "0.77.0", + "@typespec/versioning": "0.77.0", + "@typespec/openapi": "1.7.0", + "@typespec/xml": "0.77.0", + "@typespec/events": "0.77.0", + "@typespec/sse": "0.77.0", + "@typespec/streams": "0.77.0", + "@azure-tools/typespec-azure-core": "0.63.0", + "@azure-tools/typespec-client-generator-core": "0.63.0", + "@azure-tools/typespec-azure-resource-manager": "0.63.0", + "@azure-tools/typespec-autorest": "0.63.0" }, "private": true } diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/DocumentationClientBuilder.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/DocumentationClientBuilder.java new file mode 100644 index 00000000000..66fcf8f2936 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/DocumentationClientBuilder.java @@ -0,0 +1,312 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package documentation; + +import com.azure.core.annotation.Generated; +import com.azure.core.annotation.ServiceClientBuilder; +import com.azure.core.client.traits.ConfigurationTrait; +import com.azure.core.client.traits.EndpointTrait; +import com.azure.core.client.traits.HttpTrait; +import com.azure.core.http.HttpClient; +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpPipeline; +import com.azure.core.http.HttpPipelineBuilder; +import com.azure.core.http.HttpPipelinePosition; +import com.azure.core.http.policy.AddDatePolicy; +import com.azure.core.http.policy.AddHeadersFromContextPolicy; +import com.azure.core.http.policy.AddHeadersPolicy; +import com.azure.core.http.policy.HttpLogOptions; +import com.azure.core.http.policy.HttpLoggingPolicy; +import com.azure.core.http.policy.HttpPipelinePolicy; +import com.azure.core.http.policy.HttpPolicyProviders; +import com.azure.core.http.policy.RequestIdPolicy; +import com.azure.core.http.policy.RetryOptions; +import com.azure.core.http.policy.RetryPolicy; +import com.azure.core.http.policy.UserAgentPolicy; +import com.azure.core.util.ClientOptions; +import com.azure.core.util.Configuration; +import com.azure.core.util.CoreUtils; +import com.azure.core.util.builder.ClientBuilderUtil; +import com.azure.core.util.logging.ClientLogger; +import com.azure.core.util.serializer.JacksonAdapter; +import documentation.implementation.DocumentationClientImpl; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * A builder for creating a new instance of the DocumentationClient type. + */ +@ServiceClientBuilder( + serviceClients = { + ListsClient.class, + TextFormattingClient.class, + ListsAsyncClient.class, + TextFormattingAsyncClient.class }) +public final class DocumentationClientBuilder implements HttpTrait, + ConfigurationTrait, EndpointTrait { + @Generated + private static final String SDK_NAME = "name"; + + @Generated + private static final String SDK_VERSION = "version"; + + @Generated + private static final Map PROPERTIES = CoreUtils.getProperties("documentation.properties"); + + @Generated + private final List pipelinePolicies; + + /** + * Create an instance of the DocumentationClientBuilder. + */ + @Generated + public DocumentationClientBuilder() { + this.pipelinePolicies = new ArrayList<>(); + } + + /* + * The HTTP client used to send the request. + */ + @Generated + private HttpClient httpClient; + + /** + * {@inheritDoc}. + */ + @Generated + @Override + public DocumentationClientBuilder httpClient(HttpClient httpClient) { + this.httpClient = httpClient; + return this; + } + + /* + * The HTTP pipeline to send requests through. + */ + @Generated + private HttpPipeline pipeline; + + /** + * {@inheritDoc}. + */ + @Generated + @Override + public DocumentationClientBuilder pipeline(HttpPipeline pipeline) { + if (this.pipeline != null && pipeline == null) { + LOGGER.atInfo().log("HttpPipeline is being set to 'null' when it was previously configured."); + } + this.pipeline = pipeline; + return this; + } + + /* + * The logging configuration for HTTP requests and responses. + */ + @Generated + private HttpLogOptions httpLogOptions; + + /** + * {@inheritDoc}. + */ + @Generated + @Override + public DocumentationClientBuilder httpLogOptions(HttpLogOptions httpLogOptions) { + this.httpLogOptions = httpLogOptions; + return this; + } + + /* + * The client options such as application ID and custom headers to set on a request. + */ + @Generated + private ClientOptions clientOptions; + + /** + * {@inheritDoc}. + */ + @Generated + @Override + public DocumentationClientBuilder clientOptions(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + return this; + } + + /* + * The retry options to configure retry policy for failed requests. + */ + @Generated + private RetryOptions retryOptions; + + /** + * {@inheritDoc}. + */ + @Generated + @Override + public DocumentationClientBuilder retryOptions(RetryOptions retryOptions) { + this.retryOptions = retryOptions; + return this; + } + + /** + * {@inheritDoc}. + */ + @Generated + @Override + public DocumentationClientBuilder addPolicy(HttpPipelinePolicy customPolicy) { + Objects.requireNonNull(customPolicy, "'customPolicy' cannot be null."); + pipelinePolicies.add(customPolicy); + return this; + } + + /* + * The configuration store that is used during construction of the service client. + */ + @Generated + private Configuration configuration; + + /** + * {@inheritDoc}. + */ + @Generated + @Override + public DocumentationClientBuilder configuration(Configuration configuration) { + this.configuration = configuration; + return this; + } + + /* + * The service endpoint + */ + @Generated + private String endpoint; + + /** + * {@inheritDoc}. + */ + @Generated + @Override + public DocumentationClientBuilder endpoint(String endpoint) { + this.endpoint = endpoint; + return this; + } + + /* + * The retry policy that will attempt to retry failed requests, if applicable. + */ + @Generated + private RetryPolicy retryPolicy; + + /** + * Sets The retry policy that will attempt to retry failed requests, if applicable. + * + * @param retryPolicy the retryPolicy value. + * @return the DocumentationClientBuilder. + */ + @Generated + public DocumentationClientBuilder retryPolicy(RetryPolicy retryPolicy) { + this.retryPolicy = retryPolicy; + return this; + } + + /** + * Builds an instance of DocumentationClientImpl with the provided parameters. + * + * @return an instance of DocumentationClientImpl. + */ + @Generated + private DocumentationClientImpl buildInnerClient() { + this.validateClient(); + HttpPipeline localPipeline = (pipeline != null) ? pipeline : createHttpPipeline(); + String localEndpoint = (endpoint != null) ? endpoint : "http://localhost:3000"; + DocumentationClientImpl client = new DocumentationClientImpl(localPipeline, + JacksonAdapter.createDefaultSerializerAdapter(), localEndpoint); + return client; + } + + @Generated + private void validateClient() { + // This method is invoked from 'buildInnerClient'/'buildClient' method. + // Developer can customize this method, to validate that the necessary conditions are met for the new client. + } + + @Generated + private HttpPipeline createHttpPipeline() { + Configuration buildConfiguration + = (configuration == null) ? Configuration.getGlobalConfiguration() : configuration; + HttpLogOptions localHttpLogOptions = this.httpLogOptions == null ? new HttpLogOptions() : this.httpLogOptions; + ClientOptions localClientOptions = this.clientOptions == null ? new ClientOptions() : this.clientOptions; + List policies = new ArrayList<>(); + String clientName = PROPERTIES.getOrDefault(SDK_NAME, "UnknownName"); + String clientVersion = PROPERTIES.getOrDefault(SDK_VERSION, "UnknownVersion"); + String applicationId = CoreUtils.getApplicationId(localClientOptions, localHttpLogOptions); + policies.add(new UserAgentPolicy(applicationId, clientName, clientVersion, buildConfiguration)); + policies.add(new RequestIdPolicy()); + policies.add(new AddHeadersFromContextPolicy()); + HttpHeaders headers = CoreUtils.createHttpHeadersFromClientOptions(localClientOptions); + if (headers != null) { + policies.add(new AddHeadersPolicy(headers)); + } + this.pipelinePolicies.stream() + .filter(p -> p.getPipelinePosition() == HttpPipelinePosition.PER_CALL) + .forEach(p -> policies.add(p)); + HttpPolicyProviders.addBeforeRetryPolicies(policies); + policies.add(ClientBuilderUtil.validateAndGetRetryPolicy(retryPolicy, retryOptions, new RetryPolicy())); + policies.add(new AddDatePolicy()); + this.pipelinePolicies.stream() + .filter(p -> p.getPipelinePosition() == HttpPipelinePosition.PER_RETRY) + .forEach(p -> policies.add(p)); + HttpPolicyProviders.addAfterRetryPolicies(policies); + policies.add(new HttpLoggingPolicy(localHttpLogOptions)); + HttpPipeline httpPipeline = new HttpPipelineBuilder().policies(policies.toArray(new HttpPipelinePolicy[0])) + .httpClient(httpClient) + .clientOptions(localClientOptions) + .build(); + return httpPipeline; + } + + /** + * Builds an instance of ListsAsyncClient class. + * + * @return an instance of ListsAsyncClient. + */ + @Generated + public ListsAsyncClient buildListsAsyncClient() { + return new ListsAsyncClient(buildInnerClient().getLists()); + } + + /** + * Builds an instance of TextFormattingAsyncClient class. + * + * @return an instance of TextFormattingAsyncClient. + */ + @Generated + public TextFormattingAsyncClient buildTextFormattingAsyncClient() { + return new TextFormattingAsyncClient(buildInnerClient().getTextFormattings()); + } + + /** + * Builds an instance of ListsClient class. + * + * @return an instance of ListsClient. + */ + @Generated + public ListsClient buildListsClient() { + return new ListsClient(buildInnerClient().getLists()); + } + + /** + * Builds an instance of TextFormattingClient class. + * + * @return an instance of TextFormattingClient. + */ + @Generated + public TextFormattingClient buildTextFormattingClient() { + return new TextFormattingClient(buildInnerClient().getTextFormattings()); + } + + private static final ClientLogger LOGGER = new ClientLogger(DocumentationClientBuilder.class); +} diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/ListsAsyncClient.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/ListsAsyncClient.java new file mode 100644 index 00000000000..9be33080835 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/ListsAsyncClient.java @@ -0,0 +1,192 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package documentation; + +import com.azure.core.annotation.Generated; +import com.azure.core.annotation.ReturnType; +import com.azure.core.annotation.ServiceClient; +import com.azure.core.annotation.ServiceMethod; +import com.azure.core.exception.ClientAuthenticationException; +import com.azure.core.exception.HttpResponseException; +import com.azure.core.exception.ResourceModifiedException; +import com.azure.core.exception.ResourceNotFoundException; +import com.azure.core.http.rest.RequestOptions; +import com.azure.core.http.rest.Response; +import com.azure.core.util.BinaryData; +import com.azure.core.util.FluxUtil; +import documentation.implementation.ListsImpl; +import documentation.lists.implementation.models.BulletPointsModelRequest; +import documentation.lists.models.BulletPointsModel; +import reactor.core.publisher.Mono; + +/** + * Initializes a new instance of the asynchronous DocumentationClient type. + */ +@ServiceClient(builder = DocumentationClientBuilder.class, isAsync = true) +public final class ListsAsyncClient { + @Generated + private final ListsImpl serviceClient; + + /** + * Initializes an instance of ListsAsyncClient class. + * + * @param serviceClient the service client implementation. + */ + @Generated + ListsAsyncClient(ListsImpl serviceClient) { + this.serviceClient = serviceClient; + } + + /** + * This tests: + * - Simple bullet point. This bullet point is going to be very long to test how text wrapping is handled in bullet + * points within documentation comments. It should properly indent the wrapped lines. + * - Another bullet point with **bold text**. This bullet point is also intentionally long to see how the formatting + * is preserved when the text wraps onto multiple lines in the generated documentation. + * - Third bullet point with *italic text*. Similar to the previous points, this one is extended to ensure that the + * wrapping and formatting are correctly applied in the output. + * - Complex bullet point with **bold** and *italic* combined. This bullet point combines both bold and italic + * formatting and is long enough to test the wrapping behavior in such cases. + * - **Bold bullet point**: A bullet point that is entirely bolded. This point is also made lengthy to observe how + * the bold formatting is maintained across wrapped lines. + * - *Italic bullet point*: A bullet point that is entirely italicized. This final point is extended to verify that + * italic formatting is correctly applied even when the text spans multiple lines. + * + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response} on successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> bulletPointsOpWithResponse(RequestOptions requestOptions) { + return this.serviceClient.bulletPointsOpWithResponseAsync(requestOptions); + } + + /** + * The bulletPointsModel operation. + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     input (Required): {
+     *         prop: String(Simple/Bold/Italic) (Required)
+     *     }
+     * }
+     * }
+     * 
+ * + * @param bulletPointsModelRequest The bulletPointsModelRequest parameter. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response} on successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> bulletPointsModelWithResponse(BinaryData bulletPointsModelRequest, + RequestOptions requestOptions) { + return this.serviceClient.bulletPointsModelWithResponseAsync(bulletPointsModelRequest, requestOptions); + } + + /** + * Steps to follow: + * 1. First step with **important** note + * 2. Second step with *emphasis* + * 3. Third step combining **bold** and *italic* + * 4. **Final step**: Review all steps for *accuracy*. + * + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response} on successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> numberedWithResponse(RequestOptions requestOptions) { + return this.serviceClient.numberedWithResponseAsync(requestOptions); + } + + /** + * This tests: + * - Simple bullet point. This bullet point is going to be very long to test how text wrapping is handled in bullet + * points within documentation comments. It should properly indent the wrapped lines. + * - Another bullet point with **bold text**. This bullet point is also intentionally long to see how the formatting + * is preserved when the text wraps onto multiple lines in the generated documentation. + * - Third bullet point with *italic text*. Similar to the previous points, this one is extended to ensure that the + * wrapping and formatting are correctly applied in the output. + * - Complex bullet point with **bold** and *italic* combined. This bullet point combines both bold and italic + * formatting and is long enough to test the wrapping behavior in such cases. + * - **Bold bullet point**: A bullet point that is entirely bolded. This point is also made lengthy to observe how + * the bold formatting is maintained across wrapped lines. + * - *Italic bullet point*: A bullet point that is entirely italicized. This final point is extended to verify that + * italic formatting is correctly applied even when the text spans multiple lines. + * + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return A {@link Mono} that completes when a successful response is received. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono bulletPointsOp() { + // Generated convenience method for bulletPointsOpWithResponse + RequestOptions requestOptions = new RequestOptions(); + return bulletPointsOpWithResponse(requestOptions).flatMap(FluxUtil::toMono); + } + + /** + * The bulletPointsModel operation. + * + * @param input The input parameter. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return A {@link Mono} that completes when a successful response is received. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono bulletPointsModel(BulletPointsModel input) { + // Generated convenience method for bulletPointsModelWithResponse + RequestOptions requestOptions = new RequestOptions(); + BulletPointsModelRequest bulletPointsModelRequestObj = new BulletPointsModelRequest(input); + BinaryData bulletPointsModelRequest = BinaryData.fromObject(bulletPointsModelRequestObj); + return bulletPointsModelWithResponse(bulletPointsModelRequest, requestOptions).flatMap(FluxUtil::toMono); + } + + /** + * Steps to follow: + * 1. First step with **important** note + * 2. Second step with *emphasis* + * 3. Third step combining **bold** and *italic* + * 4. **Final step**: Review all steps for *accuracy*. + * + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return A {@link Mono} that completes when a successful response is received. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono numbered() { + // Generated convenience method for numberedWithResponse + RequestOptions requestOptions = new RequestOptions(); + return numberedWithResponse(requestOptions).flatMap(FluxUtil::toMono); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/ListsClient.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/ListsClient.java new file mode 100644 index 00000000000..8d609982a08 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/ListsClient.java @@ -0,0 +1,187 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package documentation; + +import com.azure.core.annotation.Generated; +import com.azure.core.annotation.ReturnType; +import com.azure.core.annotation.ServiceClient; +import com.azure.core.annotation.ServiceMethod; +import com.azure.core.exception.ClientAuthenticationException; +import com.azure.core.exception.HttpResponseException; +import com.azure.core.exception.ResourceModifiedException; +import com.azure.core.exception.ResourceNotFoundException; +import com.azure.core.http.rest.RequestOptions; +import com.azure.core.http.rest.Response; +import com.azure.core.util.BinaryData; +import documentation.implementation.ListsImpl; +import documentation.lists.implementation.models.BulletPointsModelRequest; +import documentation.lists.models.BulletPointsModel; + +/** + * Initializes a new instance of the synchronous DocumentationClient type. + */ +@ServiceClient(builder = DocumentationClientBuilder.class) +public final class ListsClient { + @Generated + private final ListsImpl serviceClient; + + /** + * Initializes an instance of ListsClient class. + * + * @param serviceClient the service client implementation. + */ + @Generated + ListsClient(ListsImpl serviceClient) { + this.serviceClient = serviceClient; + } + + /** + * This tests: + * - Simple bullet point. This bullet point is going to be very long to test how text wrapping is handled in bullet + * points within documentation comments. It should properly indent the wrapped lines. + * - Another bullet point with **bold text**. This bullet point is also intentionally long to see how the formatting + * is preserved when the text wraps onto multiple lines in the generated documentation. + * - Third bullet point with *italic text*. Similar to the previous points, this one is extended to ensure that the + * wrapping and formatting are correctly applied in the output. + * - Complex bullet point with **bold** and *italic* combined. This bullet point combines both bold and italic + * formatting and is long enough to test the wrapping behavior in such cases. + * - **Bold bullet point**: A bullet point that is entirely bolded. This point is also made lengthy to observe how + * the bold formatting is maintained across wrapped lines. + * - *Italic bullet point*: A bullet point that is entirely italicized. This final point is extended to verify that + * italic formatting is correctly applied even when the text spans multiple lines. + * + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Response bulletPointsOpWithResponse(RequestOptions requestOptions) { + return this.serviceClient.bulletPointsOpWithResponse(requestOptions); + } + + /** + * The bulletPointsModel operation. + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     input (Required): {
+     *         prop: String(Simple/Bold/Italic) (Required)
+     *     }
+     * }
+     * }
+     * 
+ * + * @param bulletPointsModelRequest The bulletPointsModelRequest parameter. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Response bulletPointsModelWithResponse(BinaryData bulletPointsModelRequest, + RequestOptions requestOptions) { + return this.serviceClient.bulletPointsModelWithResponse(bulletPointsModelRequest, requestOptions); + } + + /** + * Steps to follow: + * 1. First step with **important** note + * 2. Second step with *emphasis* + * 3. Third step combining **bold** and *italic* + * 4. **Final step**: Review all steps for *accuracy*. + * + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Response numberedWithResponse(RequestOptions requestOptions) { + return this.serviceClient.numberedWithResponse(requestOptions); + } + + /** + * This tests: + * - Simple bullet point. This bullet point is going to be very long to test how text wrapping is handled in bullet + * points within documentation comments. It should properly indent the wrapped lines. + * - Another bullet point with **bold text**. This bullet point is also intentionally long to see how the formatting + * is preserved when the text wraps onto multiple lines in the generated documentation. + * - Third bullet point with *italic text*. Similar to the previous points, this one is extended to ensure that the + * wrapping and formatting are correctly applied in the output. + * - Complex bullet point with **bold** and *italic* combined. This bullet point combines both bold and italic + * formatting and is long enough to test the wrapping behavior in such cases. + * - **Bold bullet point**: A bullet point that is entirely bolded. This point is also made lengthy to observe how + * the bold formatting is maintained across wrapped lines. + * - *Italic bullet point*: A bullet point that is entirely italicized. This final point is extended to verify that + * italic formatting is correctly applied even when the text spans multiple lines. + * + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public void bulletPointsOp() { + // Generated convenience method for bulletPointsOpWithResponse + RequestOptions requestOptions = new RequestOptions(); + bulletPointsOpWithResponse(requestOptions).getValue(); + } + + /** + * The bulletPointsModel operation. + * + * @param input The input parameter. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public void bulletPointsModel(BulletPointsModel input) { + // Generated convenience method for bulletPointsModelWithResponse + RequestOptions requestOptions = new RequestOptions(); + BulletPointsModelRequest bulletPointsModelRequestObj = new BulletPointsModelRequest(input); + BinaryData bulletPointsModelRequest = BinaryData.fromObject(bulletPointsModelRequestObj); + bulletPointsModelWithResponse(bulletPointsModelRequest, requestOptions).getValue(); + } + + /** + * Steps to follow: + * 1. First step with **important** note + * 2. Second step with *emphasis* + * 3. Third step combining **bold** and *italic* + * 4. **Final step**: Review all steps for *accuracy*. + * + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public void numbered() { + // Generated convenience method for numberedWithResponse + RequestOptions requestOptions = new RequestOptions(); + numberedWithResponse(requestOptions).getValue(); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/TextFormattingAsyncClient.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/TextFormattingAsyncClient.java new file mode 100644 index 00000000000..333f94325bd --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/TextFormattingAsyncClient.java @@ -0,0 +1,154 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package documentation; + +import com.azure.core.annotation.Generated; +import com.azure.core.annotation.ReturnType; +import com.azure.core.annotation.ServiceClient; +import com.azure.core.annotation.ServiceMethod; +import com.azure.core.exception.ClientAuthenticationException; +import com.azure.core.exception.HttpResponseException; +import com.azure.core.exception.ResourceModifiedException; +import com.azure.core.exception.ResourceNotFoundException; +import com.azure.core.http.rest.RequestOptions; +import com.azure.core.http.rest.Response; +import com.azure.core.util.FluxUtil; +import documentation.implementation.TextFormattingsImpl; +import reactor.core.publisher.Mono; + +/** + * Initializes a new instance of the asynchronous DocumentationClient type. + */ +@ServiceClient(builder = DocumentationClientBuilder.class, isAsync = true) +public final class TextFormattingAsyncClient { + @Generated + private final TextFormattingsImpl serviceClient; + + /** + * Initializes an instance of TextFormattingAsyncClient class. + * + * @param serviceClient the service client implementation. + */ + @Generated + TextFormattingAsyncClient(TextFormattingsImpl serviceClient) { + this.serviceClient = serviceClient; + } + + /** + * This is **bold text** in the middle of a sentence. + * This is a sentence with **multiple bold** sections and **another bold** section. + * **This entire sentence is bold.**. + * + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response} on successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> boldTextWithResponse(RequestOptions requestOptions) { + return this.serviceClient.boldTextWithResponseAsync(requestOptions); + } + + /** + * This is *italic text* in the middle of a sentence. + * This is a sentence with *multiple italic* sections and *another italic* section. + * *This entire sentence is italic.*. + * + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response} on successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> italicTextWithResponse(RequestOptions requestOptions) { + return this.serviceClient.italicTextWithResponseAsync(requestOptions); + } + + /** + * This sentence has **bold**, *italic*, and ***bold italic*** text. + * You can also combine them like **bold with *italic inside* bold**. + * Or *italic with **bold inside** italic*. + * This is a sentence with **bold**, *italic*, and ***bold italic*** text. + * + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response} on successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> combinedFormattingWithResponse(RequestOptions requestOptions) { + return this.serviceClient.combinedFormattingWithResponseAsync(requestOptions); + } + + /** + * This is **bold text** in the middle of a sentence. + * This is a sentence with **multiple bold** sections and **another bold** section. + * **This entire sentence is bold.**. + * + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return A {@link Mono} that completes when a successful response is received. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono boldText() { + // Generated convenience method for boldTextWithResponse + RequestOptions requestOptions = new RequestOptions(); + return boldTextWithResponse(requestOptions).flatMap(FluxUtil::toMono); + } + + /** + * This is *italic text* in the middle of a sentence. + * This is a sentence with *multiple italic* sections and *another italic* section. + * *This entire sentence is italic.*. + * + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return A {@link Mono} that completes when a successful response is received. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono italicText() { + // Generated convenience method for italicTextWithResponse + RequestOptions requestOptions = new RequestOptions(); + return italicTextWithResponse(requestOptions).flatMap(FluxUtil::toMono); + } + + /** + * This sentence has **bold**, *italic*, and ***bold italic*** text. + * You can also combine them like **bold with *italic inside* bold**. + * Or *italic with **bold inside** italic*. + * This is a sentence with **bold**, *italic*, and ***bold italic*** text. + * + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return A {@link Mono} that completes when a successful response is received. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono combinedFormatting() { + // Generated convenience method for combinedFormattingWithResponse + RequestOptions requestOptions = new RequestOptions(); + return combinedFormattingWithResponse(requestOptions).flatMap(FluxUtil::toMono); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/TextFormattingClient.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/TextFormattingClient.java new file mode 100644 index 00000000000..da0f8a3fbf6 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/TextFormattingClient.java @@ -0,0 +1,149 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package documentation; + +import com.azure.core.annotation.Generated; +import com.azure.core.annotation.ReturnType; +import com.azure.core.annotation.ServiceClient; +import com.azure.core.annotation.ServiceMethod; +import com.azure.core.exception.ClientAuthenticationException; +import com.azure.core.exception.HttpResponseException; +import com.azure.core.exception.ResourceModifiedException; +import com.azure.core.exception.ResourceNotFoundException; +import com.azure.core.http.rest.RequestOptions; +import com.azure.core.http.rest.Response; +import documentation.implementation.TextFormattingsImpl; + +/** + * Initializes a new instance of the synchronous DocumentationClient type. + */ +@ServiceClient(builder = DocumentationClientBuilder.class) +public final class TextFormattingClient { + @Generated + private final TextFormattingsImpl serviceClient; + + /** + * Initializes an instance of TextFormattingClient class. + * + * @param serviceClient the service client implementation. + */ + @Generated + TextFormattingClient(TextFormattingsImpl serviceClient) { + this.serviceClient = serviceClient; + } + + /** + * This is **bold text** in the middle of a sentence. + * This is a sentence with **multiple bold** sections and **another bold** section. + * **This entire sentence is bold.**. + * + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Response boldTextWithResponse(RequestOptions requestOptions) { + return this.serviceClient.boldTextWithResponse(requestOptions); + } + + /** + * This is *italic text* in the middle of a sentence. + * This is a sentence with *multiple italic* sections and *another italic* section. + * *This entire sentence is italic.*. + * + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Response italicTextWithResponse(RequestOptions requestOptions) { + return this.serviceClient.italicTextWithResponse(requestOptions); + } + + /** + * This sentence has **bold**, *italic*, and ***bold italic*** text. + * You can also combine them like **bold with *italic inside* bold**. + * Or *italic with **bold inside** italic*. + * This is a sentence with **bold**, *italic*, and ***bold italic*** text. + * + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Response combinedFormattingWithResponse(RequestOptions requestOptions) { + return this.serviceClient.combinedFormattingWithResponse(requestOptions); + } + + /** + * This is **bold text** in the middle of a sentence. + * This is a sentence with **multiple bold** sections and **another bold** section. + * **This entire sentence is bold.**. + * + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public void boldText() { + // Generated convenience method for boldTextWithResponse + RequestOptions requestOptions = new RequestOptions(); + boldTextWithResponse(requestOptions).getValue(); + } + + /** + * This is *italic text* in the middle of a sentence. + * This is a sentence with *multiple italic* sections and *another italic* section. + * *This entire sentence is italic.*. + * + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public void italicText() { + // Generated convenience method for italicTextWithResponse + RequestOptions requestOptions = new RequestOptions(); + italicTextWithResponse(requestOptions).getValue(); + } + + /** + * This sentence has **bold**, *italic*, and ***bold italic*** text. + * You can also combine them like **bold with *italic inside* bold**. + * Or *italic with **bold inside** italic*. + * This is a sentence with **bold**, *italic*, and ***bold italic*** text. + * + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public void combinedFormatting() { + // Generated convenience method for combinedFormattingWithResponse + RequestOptions requestOptions = new RequestOptions(); + combinedFormattingWithResponse(requestOptions).getValue(); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/implementation/DocumentationClientImpl.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/implementation/DocumentationClientImpl.java new file mode 100644 index 00000000000..e856209854a --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/implementation/DocumentationClientImpl.java @@ -0,0 +1,122 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package documentation.implementation; + +import com.azure.core.http.HttpPipeline; +import com.azure.core.http.HttpPipelineBuilder; +import com.azure.core.http.policy.RetryPolicy; +import com.azure.core.http.policy.UserAgentPolicy; +import com.azure.core.util.serializer.JacksonAdapter; +import com.azure.core.util.serializer.SerializerAdapter; + +/** + * Initializes a new instance of the DocumentationClient type. + */ +public final class DocumentationClientImpl { + /** + * Service host. + */ + private final String endpoint; + + /** + * Gets Service host. + * + * @return the endpoint value. + */ + public String getEndpoint() { + return this.endpoint; + } + + /** + * The HTTP pipeline to send requests through. + */ + private final HttpPipeline httpPipeline; + + /** + * Gets The HTTP pipeline to send requests through. + * + * @return the httpPipeline value. + */ + public HttpPipeline getHttpPipeline() { + return this.httpPipeline; + } + + /** + * The serializer to serialize an object into a string. + */ + private final SerializerAdapter serializerAdapter; + + /** + * Gets The serializer to serialize an object into a string. + * + * @return the serializerAdapter value. + */ + public SerializerAdapter getSerializerAdapter() { + return this.serializerAdapter; + } + + /** + * The ListsImpl object to access its operations. + */ + private final ListsImpl lists; + + /** + * Gets the ListsImpl object to access its operations. + * + * @return the ListsImpl object. + */ + public ListsImpl getLists() { + return this.lists; + } + + /** + * The TextFormattingsImpl object to access its operations. + */ + private final TextFormattingsImpl textFormattings; + + /** + * Gets the TextFormattingsImpl object to access its operations. + * + * @return the TextFormattingsImpl object. + */ + public TextFormattingsImpl getTextFormattings() { + return this.textFormattings; + } + + /** + * Initializes an instance of DocumentationClient client. + * + * @param endpoint Service host. + */ + public DocumentationClientImpl(String endpoint) { + this(new HttpPipelineBuilder().policies(new UserAgentPolicy(), new RetryPolicy()).build(), + JacksonAdapter.createDefaultSerializerAdapter(), endpoint); + } + + /** + * Initializes an instance of DocumentationClient client. + * + * @param httpPipeline The HTTP pipeline to send requests through. + * @param endpoint Service host. + */ + public DocumentationClientImpl(HttpPipeline httpPipeline, String endpoint) { + this(httpPipeline, JacksonAdapter.createDefaultSerializerAdapter(), endpoint); + } + + /** + * Initializes an instance of DocumentationClient client. + * + * @param httpPipeline The HTTP pipeline to send requests through. + * @param serializerAdapter The serializer to serialize an object into a string. + * @param endpoint Service host. + */ + public DocumentationClientImpl(HttpPipeline httpPipeline, SerializerAdapter serializerAdapter, String endpoint) { + this.httpPipeline = httpPipeline; + this.serializerAdapter = serializerAdapter; + this.endpoint = endpoint; + this.lists = new ListsImpl(this); + this.textFormattings = new TextFormattingsImpl(this); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/implementation/ListsImpl.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/implementation/ListsImpl.java new file mode 100644 index 00000000000..300720a0e38 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/implementation/ListsImpl.java @@ -0,0 +1,272 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package documentation.implementation; + +import com.azure.core.annotation.BodyParam; +import com.azure.core.annotation.ExpectedResponses; +import com.azure.core.annotation.Get; +import com.azure.core.annotation.HeaderParam; +import com.azure.core.annotation.Host; +import com.azure.core.annotation.HostParam; +import com.azure.core.annotation.Post; +import com.azure.core.annotation.ReturnType; +import com.azure.core.annotation.ServiceInterface; +import com.azure.core.annotation.ServiceMethod; +import com.azure.core.annotation.UnexpectedResponseExceptionType; +import com.azure.core.exception.ClientAuthenticationException; +import com.azure.core.exception.HttpResponseException; +import com.azure.core.exception.ResourceModifiedException; +import com.azure.core.exception.ResourceNotFoundException; +import com.azure.core.http.rest.RequestOptions; +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.RestProxy; +import com.azure.core.util.BinaryData; +import com.azure.core.util.Context; +import com.azure.core.util.FluxUtil; +import reactor.core.publisher.Mono; + +/** + * An instance of this class provides access to all the operations defined in Lists. + */ +public final class ListsImpl { + /** + * The proxy service used to perform REST calls. + */ + private final ListsService service; + + /** + * The service client containing this operation class. + */ + private final DocumentationClientImpl client; + + /** + * Initializes an instance of ListsImpl. + * + * @param client the instance of the service client containing this operation class. + */ + ListsImpl(DocumentationClientImpl client) { + this.service = RestProxy.create(ListsService.class, client.getHttpPipeline(), client.getSerializerAdapter()); + this.client = client; + } + + /** + * The interface defining all the services for DocumentationClientLists to be used by the proxy service to perform + * REST calls. + */ + @Host("{endpoint}") + @ServiceInterface(name = "DocumentationClientLists") + public interface ListsService { + @Get("/documentation/lists/bullet-points/op") + @ExpectedResponses({ 204 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> bulletPointsOp(@HostParam("endpoint") String endpoint, RequestOptions requestOptions, + Context context); + + @Get("/documentation/lists/bullet-points/op") + @ExpectedResponses({ 204 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Response bulletPointsOpSync(@HostParam("endpoint") String endpoint, RequestOptions requestOptions, + Context context); + + @Post("/documentation/lists/bullet-points/model") + @ExpectedResponses({ 204 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> bulletPointsModel(@HostParam("endpoint") String endpoint, + @HeaderParam("Content-Type") String contentType, + @BodyParam("application/json") BinaryData bulletPointsModelRequest, RequestOptions requestOptions, + Context context); + + @Post("/documentation/lists/bullet-points/model") + @ExpectedResponses({ 204 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Response bulletPointsModelSync(@HostParam("endpoint") String endpoint, + @HeaderParam("Content-Type") String contentType, + @BodyParam("application/json") BinaryData bulletPointsModelRequest, RequestOptions requestOptions, + Context context); + + @Get("/documentation/lists/numbered") + @ExpectedResponses({ 204 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> numbered(@HostParam("endpoint") String endpoint, RequestOptions requestOptions, + Context context); + + @Get("/documentation/lists/numbered") + @ExpectedResponses({ 204 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Response numberedSync(@HostParam("endpoint") String endpoint, RequestOptions requestOptions, + Context context); + } + + /** + * This tests: + * - Simple bullet point. This bullet point is going to be very long to test how text wrapping is handled in bullet + * points within documentation comments. It should properly indent the wrapped lines. + * - Another bullet point with **bold text**. This bullet point is also intentionally long to see how the formatting + * is preserved when the text wraps onto multiple lines in the generated documentation. + * - Third bullet point with *italic text*. Similar to the previous points, this one is extended to ensure that the + * wrapping and formatting are correctly applied in the output. + * - Complex bullet point with **bold** and *italic* combined. This bullet point combines both bold and italic + * formatting and is long enough to test the wrapping behavior in such cases. + * - **Bold bullet point**: A bullet point that is entirely bolded. This point is also made lengthy to observe how + * the bold formatting is maintained across wrapped lines. + * - *Italic bullet point*: A bullet point that is entirely italicized. This final point is extended to verify that + * italic formatting is correctly applied even when the text spans multiple lines. + * + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response} on successful completion of {@link Mono}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> bulletPointsOpWithResponseAsync(RequestOptions requestOptions) { + return FluxUtil + .withContext(context -> service.bulletPointsOp(this.client.getEndpoint(), requestOptions, context)); + } + + /** + * This tests: + * - Simple bullet point. This bullet point is going to be very long to test how text wrapping is handled in bullet + * points within documentation comments. It should properly indent the wrapped lines. + * - Another bullet point with **bold text**. This bullet point is also intentionally long to see how the formatting + * is preserved when the text wraps onto multiple lines in the generated documentation. + * - Third bullet point with *italic text*. Similar to the previous points, this one is extended to ensure that the + * wrapping and formatting are correctly applied in the output. + * - Complex bullet point with **bold** and *italic* combined. This bullet point combines both bold and italic + * formatting and is long enough to test the wrapping behavior in such cases. + * - **Bold bullet point**: A bullet point that is entirely bolded. This point is also made lengthy to observe how + * the bold formatting is maintained across wrapped lines. + * - *Italic bullet point*: A bullet point that is entirely italicized. This final point is extended to verify that + * italic formatting is correctly applied even when the text spans multiple lines. + * + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response bulletPointsOpWithResponse(RequestOptions requestOptions) { + return service.bulletPointsOpSync(this.client.getEndpoint(), requestOptions, Context.NONE); + } + + /** + * The bulletPointsModel operation. + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     input (Required): {
+     *         prop: String(Simple/Bold/Italic) (Required)
+     *     }
+     * }
+     * }
+     * 
+ * + * @param bulletPointsModelRequest The bulletPointsModelRequest parameter. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response} on successful completion of {@link Mono}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> bulletPointsModelWithResponseAsync(BinaryData bulletPointsModelRequest, + RequestOptions requestOptions) { + final String contentType = "application/json"; + return FluxUtil.withContext(context -> service.bulletPointsModel(this.client.getEndpoint(), contentType, + bulletPointsModelRequest, requestOptions, context)); + } + + /** + * The bulletPointsModel operation. + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     input (Required): {
+     *         prop: String(Simple/Bold/Italic) (Required)
+     *     }
+     * }
+     * }
+     * 
+ * + * @param bulletPointsModelRequest The bulletPointsModelRequest parameter. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response bulletPointsModelWithResponse(BinaryData bulletPointsModelRequest, + RequestOptions requestOptions) { + final String contentType = "application/json"; + return service.bulletPointsModelSync(this.client.getEndpoint(), contentType, bulletPointsModelRequest, + requestOptions, Context.NONE); + } + + /** + * Steps to follow: + * 1. First step with **important** note + * 2. Second step with *emphasis* + * 3. Third step combining **bold** and *italic* + * 4. **Final step**: Review all steps for *accuracy*. + * + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response} on successful completion of {@link Mono}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> numberedWithResponseAsync(RequestOptions requestOptions) { + return FluxUtil.withContext(context -> service.numbered(this.client.getEndpoint(), requestOptions, context)); + } + + /** + * Steps to follow: + * 1. First step with **important** note + * 2. Second step with *emphasis* + * 3. Third step combining **bold** and *italic* + * 4. **Final step**: Review all steps for *accuracy*. + * + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response numberedWithResponse(RequestOptions requestOptions) { + return service.numberedSync(this.client.getEndpoint(), requestOptions, Context.NONE); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/implementation/TextFormattingsImpl.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/implementation/TextFormattingsImpl.java new file mode 100644 index 00000000000..714c5ca8436 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/implementation/TextFormattingsImpl.java @@ -0,0 +1,217 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package documentation.implementation; + +import com.azure.core.annotation.ExpectedResponses; +import com.azure.core.annotation.Get; +import com.azure.core.annotation.Host; +import com.azure.core.annotation.HostParam; +import com.azure.core.annotation.ReturnType; +import com.azure.core.annotation.ServiceInterface; +import com.azure.core.annotation.ServiceMethod; +import com.azure.core.annotation.UnexpectedResponseExceptionType; +import com.azure.core.exception.ClientAuthenticationException; +import com.azure.core.exception.HttpResponseException; +import com.azure.core.exception.ResourceModifiedException; +import com.azure.core.exception.ResourceNotFoundException; +import com.azure.core.http.rest.RequestOptions; +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.RestProxy; +import com.azure.core.util.Context; +import com.azure.core.util.FluxUtil; +import reactor.core.publisher.Mono; + +/** + * An instance of this class provides access to all the operations defined in TextFormattings. + */ +public final class TextFormattingsImpl { + /** + * The proxy service used to perform REST calls. + */ + private final TextFormattingsService service; + + /** + * The service client containing this operation class. + */ + private final DocumentationClientImpl client; + + /** + * Initializes an instance of TextFormattingsImpl. + * + * @param client the instance of the service client containing this operation class. + */ + TextFormattingsImpl(DocumentationClientImpl client) { + this.service + = RestProxy.create(TextFormattingsService.class, client.getHttpPipeline(), client.getSerializerAdapter()); + this.client = client; + } + + /** + * The interface defining all the services for DocumentationClientTextFormattings to be used by the proxy service to + * perform REST calls. + */ + @Host("{endpoint}") + @ServiceInterface(name = "DocumentationClientTextFormattings") + public interface TextFormattingsService { + @Get("/documentation/text-formatting/bold") + @ExpectedResponses({ 204 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> boldText(@HostParam("endpoint") String endpoint, RequestOptions requestOptions, + Context context); + + @Get("/documentation/text-formatting/bold") + @ExpectedResponses({ 204 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Response boldTextSync(@HostParam("endpoint") String endpoint, RequestOptions requestOptions, + Context context); + + @Get("/documentation/text-formatting/italic") + @ExpectedResponses({ 204 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> italicText(@HostParam("endpoint") String endpoint, RequestOptions requestOptions, + Context context); + + @Get("/documentation/text-formatting/italic") + @ExpectedResponses({ 204 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Response italicTextSync(@HostParam("endpoint") String endpoint, RequestOptions requestOptions, + Context context); + + @Get("/documentation/text-formatting/combined") + @ExpectedResponses({ 204 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> combinedFormatting(@HostParam("endpoint") String endpoint, RequestOptions requestOptions, + Context context); + + @Get("/documentation/text-formatting/combined") + @ExpectedResponses({ 204 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Response combinedFormattingSync(@HostParam("endpoint") String endpoint, RequestOptions requestOptions, + Context context); + } + + /** + * This is **bold text** in the middle of a sentence. + * This is a sentence with **multiple bold** sections and **another bold** section. + * **This entire sentence is bold.**. + * + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response} on successful completion of {@link Mono}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> boldTextWithResponseAsync(RequestOptions requestOptions) { + return FluxUtil.withContext(context -> service.boldText(this.client.getEndpoint(), requestOptions, context)); + } + + /** + * This is **bold text** in the middle of a sentence. + * This is a sentence with **multiple bold** sections and **another bold** section. + * **This entire sentence is bold.**. + * + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response boldTextWithResponse(RequestOptions requestOptions) { + return service.boldTextSync(this.client.getEndpoint(), requestOptions, Context.NONE); + } + + /** + * This is *italic text* in the middle of a sentence. + * This is a sentence with *multiple italic* sections and *another italic* section. + * *This entire sentence is italic.*. + * + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response} on successful completion of {@link Mono}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> italicTextWithResponseAsync(RequestOptions requestOptions) { + return FluxUtil.withContext(context -> service.italicText(this.client.getEndpoint(), requestOptions, context)); + } + + /** + * This is *italic text* in the middle of a sentence. + * This is a sentence with *multiple italic* sections and *another italic* section. + * *This entire sentence is italic.*. + * + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response italicTextWithResponse(RequestOptions requestOptions) { + return service.italicTextSync(this.client.getEndpoint(), requestOptions, Context.NONE); + } + + /** + * This sentence has **bold**, *italic*, and ***bold italic*** text. + * You can also combine them like **bold with *italic inside* bold**. + * Or *italic with **bold inside** italic*. + * This is a sentence with **bold**, *italic*, and ***bold italic*** text. + * + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response} on successful completion of {@link Mono}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> combinedFormattingWithResponseAsync(RequestOptions requestOptions) { + return FluxUtil + .withContext(context -> service.combinedFormatting(this.client.getEndpoint(), requestOptions, context)); + } + + /** + * This sentence has **bold**, *italic*, and ***bold italic*** text. + * You can also combine them like **bold with *italic inside* bold**. + * Or *italic with **bold inside** italic*. + * This is a sentence with **bold**, *italic*, and ***bold italic*** text. + * + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response combinedFormattingWithResponse(RequestOptions requestOptions) { + return service.combinedFormattingSync(this.client.getEndpoint(), requestOptions, Context.NONE); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/implementation/package-info.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/implementation/package-info.java new file mode 100644 index 00000000000..cf5c015aeea --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/implementation/package-info.java @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +/** + * + * Package containing the implementations for Documentation. + * Illustrates documentation generation and formatting features. + * + */ +package documentation.implementation; diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/lists/implementation/models/BulletPointsModelRequest.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/lists/implementation/models/BulletPointsModelRequest.java new file mode 100644 index 00000000000..33c31b8319a --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/lists/implementation/models/BulletPointsModelRequest.java @@ -0,0 +1,84 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package documentation.lists.implementation.models; + +import com.azure.core.annotation.Generated; +import com.azure.core.annotation.Immutable; +import com.azure.json.JsonReader; +import com.azure.json.JsonSerializable; +import com.azure.json.JsonToken; +import com.azure.json.JsonWriter; +import documentation.lists.models.BulletPointsModel; +import java.io.IOException; + +/** + * The BulletPointsModelRequest model. + */ +@Immutable +public final class BulletPointsModelRequest implements JsonSerializable { + /* + * The input property. + */ + @Generated + private final BulletPointsModel input; + + /** + * Creates an instance of BulletPointsModelRequest class. + * + * @param input the input value to set. + */ + @Generated + public BulletPointsModelRequest(BulletPointsModel input) { + this.input = input; + } + + /** + * Get the input property: The input property. + * + * @return the input value. + */ + @Generated + public BulletPointsModel getInput() { + return this.input; + } + + /** + * {@inheritDoc} + */ + @Generated + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + jsonWriter.writeJsonField("input", this.input); + return jsonWriter.writeEndObject(); + } + + /** + * Reads an instance of BulletPointsModelRequest from the JsonReader. + * + * @param jsonReader The JsonReader being read. + * @return An instance of BulletPointsModelRequest if the JsonReader was pointing to an instance of it, or null if + * it was pointing to JSON null. + * @throws IllegalStateException If the deserialized JSON object was missing any required properties. + * @throws IOException If an error occurs while reading the BulletPointsModelRequest. + */ + @Generated + public static BulletPointsModelRequest fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject(reader -> { + BulletPointsModel input = null; + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("input".equals(fieldName)) { + input = BulletPointsModel.fromJson(reader); + } else { + reader.skipChildren(); + } + } + return new BulletPointsModelRequest(input); + }); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/lists/implementation/models/package-info.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/lists/implementation/models/package-info.java new file mode 100644 index 00000000000..14161731cbc --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/lists/implementation/models/package-info.java @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +/** + * + * Package containing the data models for Documentation. + * Illustrates documentation generation and formatting features. + * + */ +package documentation.lists.implementation.models; diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/lists/models/BulletPointsEnum.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/lists/models/BulletPointsEnum.java new file mode 100644 index 00000000000..cc5f71d6248 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/lists/models/BulletPointsEnum.java @@ -0,0 +1,89 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package documentation.lists.models; + +/** + * This tests really long bullet points in enum documentation to see how wrapping and formatting are handled. This + * should wrap around correctly and maintain proper indentation for each line. + * - Simple bullet point. This bullet point is going to be very long to test how text wrapping is handled in bullet + * points within documentation comments. It should properly indent the wrapped lines. + * - Another bullet point with **bold text**. This bullet point is also intentionally long to see how the formatting is + * preserved when the text wraps onto multiple lines in the generated documentation. + * - Third bullet point with *italic text*. Similar to the previous points, this one is extended to ensure that the + * wrapping and formatting are correctly applied in the output. + * - Complex bullet point with **bold** and *italic* combined. This bullet point combines both bold and italic + * formatting and is long enough to test the wrapping behavior in such cases. + * - **Bold bullet point**: A bullet point that is entirely bolded. This point is also made lengthy to observe how the + * bold formatting is maintained across wrapped lines. + * - *Italic bullet point*: A bullet point that is entirely italicized. This final point is extended to verify that + * italic formatting is correctly applied even when the text spans multiple lines. + */ +public enum BulletPointsEnum { + /** + * Simple bullet point. This line is intentionally long to test text wrapping in bullet points within enum + * documentation comments. It should properly indent the wrapped lines. + * - One: one. This line is intentionally long to test text wrapping in bullet points within enum documentation + * comments. It should properly indent the wrapped lines. + * - Two: two. This line is intentionally long to test text wrapping in bullet points within enum documentation + * comments. It should properly indent the wrapped lines. + */ + SIMPLE("Simple"), + + /** + * Bullet point with **bold text**. This line is intentionally long to test text wrapping in bullet points within + * enum documentation comments. It should properly indent the wrapped lines. + * - **One**: one. This line is intentionally long to test text wrapping in bullet points within enum documentation + * comments. It should properly indent the wrapped lines. + * - **Two**: two. This line is intentionally long to test text wrapping in bullet points within enum documentation + * comments. It should properly indent the wrapped lines. + */ + BOLD("Bold"), + + /** + * Bullet point with *italic text*. This line is intentionally long to test text wrapping in bullet points within + * enum documentation comments. It should properly indent the wrapped lines. + * - *One*: one. This line is intentionally long to test text wrapping in bullet points within enum documentation + * comments. It should properly indent the wrapped lines. + * - *Two*: two. This line is intentionally long to test text wrapping in bullet points within enum documentation + * comments. It should properly indent the wrapped lines. + */ + ITALIC("Italic"); + + /** + * The actual serialized value for a BulletPointsEnum instance. + */ + private final String value; + + BulletPointsEnum(String value) { + this.value = value; + } + + /** + * Parses a serialized value to a BulletPointsEnum instance. + * + * @param value the serialized value to parse. + * @return the parsed BulletPointsEnum object, or null if unable to parse. + */ + public static BulletPointsEnum fromString(String value) { + if (value == null) { + return null; + } + BulletPointsEnum[] items = BulletPointsEnum.values(); + for (BulletPointsEnum item : items) { + if (item.toString().equalsIgnoreCase(value)) { + return item; + } + } + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return this.value; + } +} diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/lists/models/BulletPointsModel.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/lists/models/BulletPointsModel.java new file mode 100644 index 00000000000..7d67f328555 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/lists/models/BulletPointsModel.java @@ -0,0 +1,117 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package documentation.lists.models; + +import com.azure.core.annotation.Generated; +import com.azure.core.annotation.Immutable; +import com.azure.json.JsonReader; +import com.azure.json.JsonSerializable; +import com.azure.json.JsonToken; +import com.azure.json.JsonWriter; +import java.io.IOException; + +/** + * This tests: + * - Simple bullet point. This bullet point is going to be very long to test how text wrapping is handled in bullet + * points within documentation comments. It should properly indent the wrapped lines. + * - Another bullet point with **bold text**. This bullet point is also intentionally long to see how the formatting is + * preserved when the text wraps onto multiple lines in the generated documentation. + * - Third bullet point with *italic text*. Similar to the previous points, this one is extended to ensure that the + * wrapping and formatting are correctly applied in the output. + * - Complex bullet point with **bold** and *italic* combined. This bullet point combines both bold and italic + * formatting and is long enough to test the wrapping behavior in such cases. + * - **Bold bullet point**: A bullet point that is entirely bolded. This point is also made lengthy to observe how the + * bold formatting is maintained across wrapped lines. + * - *Italic bullet point*: A bullet point that is entirely italicized. This final point is extended to verify that + * italic formatting is correctly applied even when the text spans multiple lines. + */ +@Immutable +public final class BulletPointsModel implements JsonSerializable { + /* + * This property uses an enum with bullet point documentation. The enum documentation includes various formatting + * styles to test rendering. The styles are: + * - Simple bullet point. This bullet point is going to be very long to test how text wrapping is handled in bullet + * points within documentation comments. It should properly indent the wrapped lines. + * - Bullet point with **bold text**. This bullet point is also intentionally long to see how the formatting is + * preserved when the text wraps onto multiple + * - Bullet point with *italic text*. Similar to the previous points, this one is extended to ensure that the + * wrapping and formatting are correctly applied in the output. + * - Complex bullet point with **bold** and *italic* combined. This bullet point combines both bold and italic + * formatting and is long enough to test the wrapping behavior in such cases. + * - **Bold bullet point** + * - *Italic bullet point* + */ + @Generated + private final BulletPointsEnum prop; + + /** + * Creates an instance of BulletPointsModel class. + * + * @param prop the prop value to set. + */ + @Generated + public BulletPointsModel(BulletPointsEnum prop) { + this.prop = prop; + } + + /** + * Get the prop property: This property uses an enum with bullet point documentation. The enum documentation + * includes various formatting styles to test rendering. The styles are: + * - Simple bullet point. This bullet point is going to be very long to test how text wrapping is handled in bullet + * points within documentation comments. It should properly indent the wrapped lines. + * - Bullet point with **bold text**. This bullet point is also intentionally long to see how the formatting is + * preserved when the text wraps onto multiple + * - Bullet point with *italic text*. Similar to the previous points, this one is extended to ensure that the + * wrapping and formatting are correctly applied in the output. + * - Complex bullet point with **bold** and *italic* combined. This bullet point combines both bold and italic + * formatting and is long enough to test the wrapping behavior in such cases. + * - **Bold bullet point** + * - *Italic bullet point*. + * + * @return the prop value. + */ + @Generated + public BulletPointsEnum getProp() { + return this.prop; + } + + /** + * {@inheritDoc} + */ + @Generated + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + jsonWriter.writeStringField("prop", this.prop == null ? null : this.prop.toString()); + return jsonWriter.writeEndObject(); + } + + /** + * Reads an instance of BulletPointsModel from the JsonReader. + * + * @param jsonReader The JsonReader being read. + * @return An instance of BulletPointsModel if the JsonReader was pointing to an instance of it, or null if it was + * pointing to JSON null. + * @throws IllegalStateException If the deserialized JSON object was missing any required properties. + * @throws IOException If an error occurs while reading the BulletPointsModel. + */ + @Generated + public static BulletPointsModel fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject(reader -> { + BulletPointsEnum prop = null; + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("prop".equals(fieldName)) { + prop = BulletPointsEnum.fromString(reader.getString()); + } else { + reader.skipChildren(); + } + } + return new BulletPointsModel(prop); + }); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/lists/models/package-info.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/lists/models/package-info.java new file mode 100644 index 00000000000..18b20f6214a --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/lists/models/package-info.java @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +/** + * + * Package containing the data models for Documentation. + * Illustrates documentation generation and formatting features. + * + */ +package documentation.lists.models; diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/package-info.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/package-info.java new file mode 100644 index 00000000000..c1de9ece111 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/documentation/package-info.java @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +/** + * + * Package containing the classes for Documentation. + * Illustrates documentation generation and formatting features. + * + */ +package documentation; diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/ArrayAsyncClient.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/ArrayAsyncClient.java new file mode 100644 index 00000000000..c1f61049463 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/ArrayAsyncClient.java @@ -0,0 +1,287 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package encode.array; + +import com.azure.core.annotation.Generated; +import com.azure.core.annotation.ReturnType; +import com.azure.core.annotation.ServiceClient; +import com.azure.core.annotation.ServiceMethod; +import com.azure.core.exception.ClientAuthenticationException; +import com.azure.core.exception.HttpResponseException; +import com.azure.core.exception.ResourceModifiedException; +import com.azure.core.exception.ResourceNotFoundException; +import com.azure.core.http.rest.RequestOptions; +import com.azure.core.http.rest.Response; +import com.azure.core.util.BinaryData; +import com.azure.core.util.FluxUtil; +import encode.array.implementation.PropertiesImpl; +import encode.array.models.CommaDelimitedArrayProperty; +import encode.array.models.NewlineDelimitedArrayProperty; +import encode.array.models.PipeDelimitedArrayProperty; +import encode.array.models.SpaceDelimitedArrayProperty; +import reactor.core.publisher.Mono; + +/** + * Initializes a new instance of the asynchronous ArrayClient type. + */ +@ServiceClient(builder = ArrayClientBuilder.class, isAsync = true) +public final class ArrayAsyncClient { + @Generated + private final PropertiesImpl serviceClient; + + /** + * Initializes an instance of ArrayAsyncClient class. + * + * @param serviceClient the service client implementation. + */ + @Generated + ArrayAsyncClient(PropertiesImpl serviceClient) { + this.serviceClient = serviceClient; + } + + /** + * The commaDelimited operation. + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     value (Required): [
+     *         String (Required)
+     *     ]
+     * }
+     * }
+     * 
+ * + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     value (Required): [
+     *         String (Required)
+     *     ]
+     * }
+     * }
+     * 
+ * + * @param body The body parameter. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the response body along with {@link Response} on successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> commaDelimitedWithResponse(BinaryData body, RequestOptions requestOptions) { + return this.serviceClient.commaDelimitedWithResponseAsync(body, requestOptions); + } + + /** + * The spaceDelimited operation. + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     value (Required): [
+     *         String (Required)
+     *     ]
+     * }
+     * }
+     * 
+ * + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     value (Required): [
+     *         String (Required)
+     *     ]
+     * }
+     * }
+     * 
+ * + * @param body The body parameter. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the response body along with {@link Response} on successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> spaceDelimitedWithResponse(BinaryData body, RequestOptions requestOptions) { + return this.serviceClient.spaceDelimitedWithResponseAsync(body, requestOptions); + } + + /** + * The pipeDelimited operation. + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     value (Required): [
+     *         String (Required)
+     *     ]
+     * }
+     * }
+     * 
+ * + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     value (Required): [
+     *         String (Required)
+     *     ]
+     * }
+     * }
+     * 
+ * + * @param body The body parameter. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the response body along with {@link Response} on successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> pipeDelimitedWithResponse(BinaryData body, RequestOptions requestOptions) { + return this.serviceClient.pipeDelimitedWithResponseAsync(body, requestOptions); + } + + /** + * The newlineDelimited operation. + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     value (Required): [
+     *         String (Required)
+     *     ]
+     * }
+     * }
+     * 
+ * + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     value (Required): [
+     *         String (Required)
+     *     ]
+     * }
+     * }
+     * 
+ * + * @param body The body parameter. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the response body along with {@link Response} on successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> newlineDelimitedWithResponse(BinaryData body, RequestOptions requestOptions) { + return this.serviceClient.newlineDelimitedWithResponseAsync(body, requestOptions); + } + + /** + * The commaDelimited operation. + * + * @param body The body parameter. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response body on successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono commaDelimited(CommaDelimitedArrayProperty body) { + // Generated convenience method for commaDelimitedWithResponse + RequestOptions requestOptions = new RequestOptions(); + return commaDelimitedWithResponse(BinaryData.fromObject(body), requestOptions).flatMap(FluxUtil::toMono) + .map(protocolMethodData -> protocolMethodData.toObject(CommaDelimitedArrayProperty.class)); + } + + /** + * The spaceDelimited operation. + * + * @param body The body parameter. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response body on successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono spaceDelimited(SpaceDelimitedArrayProperty body) { + // Generated convenience method for spaceDelimitedWithResponse + RequestOptions requestOptions = new RequestOptions(); + return spaceDelimitedWithResponse(BinaryData.fromObject(body), requestOptions).flatMap(FluxUtil::toMono) + .map(protocolMethodData -> protocolMethodData.toObject(SpaceDelimitedArrayProperty.class)); + } + + /** + * The pipeDelimited operation. + * + * @param body The body parameter. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response body on successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono pipeDelimited(PipeDelimitedArrayProperty body) { + // Generated convenience method for pipeDelimitedWithResponse + RequestOptions requestOptions = new RequestOptions(); + return pipeDelimitedWithResponse(BinaryData.fromObject(body), requestOptions).flatMap(FluxUtil::toMono) + .map(protocolMethodData -> protocolMethodData.toObject(PipeDelimitedArrayProperty.class)); + } + + /** + * The newlineDelimited operation. + * + * @param body The body parameter. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response body on successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono newlineDelimited(NewlineDelimitedArrayProperty body) { + // Generated convenience method for newlineDelimitedWithResponse + RequestOptions requestOptions = new RequestOptions(); + return newlineDelimitedWithResponse(BinaryData.fromObject(body), requestOptions).flatMap(FluxUtil::toMono) + .map(protocolMethodData -> protocolMethodData.toObject(NewlineDelimitedArrayProperty.class)); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/ArrayClient.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/ArrayClient.java new file mode 100644 index 00000000000..eba503c660f --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/ArrayClient.java @@ -0,0 +1,285 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package encode.array; + +import com.azure.core.annotation.Generated; +import com.azure.core.annotation.ReturnType; +import com.azure.core.annotation.ServiceClient; +import com.azure.core.annotation.ServiceMethod; +import com.azure.core.exception.ClientAuthenticationException; +import com.azure.core.exception.HttpResponseException; +import com.azure.core.exception.ResourceModifiedException; +import com.azure.core.exception.ResourceNotFoundException; +import com.azure.core.http.rest.RequestOptions; +import com.azure.core.http.rest.Response; +import com.azure.core.util.BinaryData; +import encode.array.implementation.PropertiesImpl; +import encode.array.models.CommaDelimitedArrayProperty; +import encode.array.models.NewlineDelimitedArrayProperty; +import encode.array.models.PipeDelimitedArrayProperty; +import encode.array.models.SpaceDelimitedArrayProperty; + +/** + * Initializes a new instance of the synchronous ArrayClient type. + */ +@ServiceClient(builder = ArrayClientBuilder.class) +public final class ArrayClient { + @Generated + private final PropertiesImpl serviceClient; + + /** + * Initializes an instance of ArrayClient class. + * + * @param serviceClient the service client implementation. + */ + @Generated + ArrayClient(PropertiesImpl serviceClient) { + this.serviceClient = serviceClient; + } + + /** + * The commaDelimited operation. + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     value (Required): [
+     *         String (Required)
+     *     ]
+     * }
+     * }
+     * 
+ * + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     value (Required): [
+     *         String (Required)
+     *     ]
+     * }
+     * }
+     * 
+ * + * @param body The body parameter. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the response body along with {@link Response}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Response commaDelimitedWithResponse(BinaryData body, RequestOptions requestOptions) { + return this.serviceClient.commaDelimitedWithResponse(body, requestOptions); + } + + /** + * The spaceDelimited operation. + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     value (Required): [
+     *         String (Required)
+     *     ]
+     * }
+     * }
+     * 
+ * + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     value (Required): [
+     *         String (Required)
+     *     ]
+     * }
+     * }
+     * 
+ * + * @param body The body parameter. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the response body along with {@link Response}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Response spaceDelimitedWithResponse(BinaryData body, RequestOptions requestOptions) { + return this.serviceClient.spaceDelimitedWithResponse(body, requestOptions); + } + + /** + * The pipeDelimited operation. + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     value (Required): [
+     *         String (Required)
+     *     ]
+     * }
+     * }
+     * 
+ * + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     value (Required): [
+     *         String (Required)
+     *     ]
+     * }
+     * }
+     * 
+ * + * @param body The body parameter. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the response body along with {@link Response}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Response pipeDelimitedWithResponse(BinaryData body, RequestOptions requestOptions) { + return this.serviceClient.pipeDelimitedWithResponse(body, requestOptions); + } + + /** + * The newlineDelimited operation. + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     value (Required): [
+     *         String (Required)
+     *     ]
+     * }
+     * }
+     * 
+ * + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     value (Required): [
+     *         String (Required)
+     *     ]
+     * }
+     * }
+     * 
+ * + * @param body The body parameter. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the response body along with {@link Response}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Response newlineDelimitedWithResponse(BinaryData body, RequestOptions requestOptions) { + return this.serviceClient.newlineDelimitedWithResponse(body, requestOptions); + } + + /** + * The commaDelimited operation. + * + * @param body The body parameter. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public CommaDelimitedArrayProperty commaDelimited(CommaDelimitedArrayProperty body) { + // Generated convenience method for commaDelimitedWithResponse + RequestOptions requestOptions = new RequestOptions(); + return commaDelimitedWithResponse(BinaryData.fromObject(body), requestOptions).getValue() + .toObject(CommaDelimitedArrayProperty.class); + } + + /** + * The spaceDelimited operation. + * + * @param body The body parameter. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public SpaceDelimitedArrayProperty spaceDelimited(SpaceDelimitedArrayProperty body) { + // Generated convenience method for spaceDelimitedWithResponse + RequestOptions requestOptions = new RequestOptions(); + return spaceDelimitedWithResponse(BinaryData.fromObject(body), requestOptions).getValue() + .toObject(SpaceDelimitedArrayProperty.class); + } + + /** + * The pipeDelimited operation. + * + * @param body The body parameter. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public PipeDelimitedArrayProperty pipeDelimited(PipeDelimitedArrayProperty body) { + // Generated convenience method for pipeDelimitedWithResponse + RequestOptions requestOptions = new RequestOptions(); + return pipeDelimitedWithResponse(BinaryData.fromObject(body), requestOptions).getValue() + .toObject(PipeDelimitedArrayProperty.class); + } + + /** + * The newlineDelimited operation. + * + * @param body The body parameter. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public NewlineDelimitedArrayProperty newlineDelimited(NewlineDelimitedArrayProperty body) { + // Generated convenience method for newlineDelimitedWithResponse + RequestOptions requestOptions = new RequestOptions(); + return newlineDelimitedWithResponse(BinaryData.fromObject(body), requestOptions).getValue() + .toObject(NewlineDelimitedArrayProperty.class); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/ArrayClientBuilder.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/ArrayClientBuilder.java new file mode 100644 index 00000000000..e2ea5c59755 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/ArrayClientBuilder.java @@ -0,0 +1,287 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package encode.array; + +import com.azure.core.annotation.Generated; +import com.azure.core.annotation.ServiceClientBuilder; +import com.azure.core.client.traits.ConfigurationTrait; +import com.azure.core.client.traits.EndpointTrait; +import com.azure.core.client.traits.HttpTrait; +import com.azure.core.http.HttpClient; +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpPipeline; +import com.azure.core.http.HttpPipelineBuilder; +import com.azure.core.http.HttpPipelinePosition; +import com.azure.core.http.policy.AddDatePolicy; +import com.azure.core.http.policy.AddHeadersFromContextPolicy; +import com.azure.core.http.policy.AddHeadersPolicy; +import com.azure.core.http.policy.HttpLogOptions; +import com.azure.core.http.policy.HttpLoggingPolicy; +import com.azure.core.http.policy.HttpPipelinePolicy; +import com.azure.core.http.policy.HttpPolicyProviders; +import com.azure.core.http.policy.RequestIdPolicy; +import com.azure.core.http.policy.RetryOptions; +import com.azure.core.http.policy.RetryPolicy; +import com.azure.core.http.policy.UserAgentPolicy; +import com.azure.core.util.ClientOptions; +import com.azure.core.util.Configuration; +import com.azure.core.util.CoreUtils; +import com.azure.core.util.builder.ClientBuilderUtil; +import com.azure.core.util.logging.ClientLogger; +import com.azure.core.util.serializer.JacksonAdapter; +import encode.array.implementation.ArrayClientImpl; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * A builder for creating a new instance of the ArrayClient type. + */ +@ServiceClientBuilder(serviceClients = { ArrayClient.class, ArrayAsyncClient.class }) +public final class ArrayClientBuilder implements HttpTrait, ConfigurationTrait, + EndpointTrait { + @Generated + private static final String SDK_NAME = "name"; + + @Generated + private static final String SDK_VERSION = "version"; + + @Generated + private static final Map PROPERTIES = CoreUtils.getProperties("encode-array.properties"); + + @Generated + private final List pipelinePolicies; + + /** + * Create an instance of the ArrayClientBuilder. + */ + @Generated + public ArrayClientBuilder() { + this.pipelinePolicies = new ArrayList<>(); + } + + /* + * The HTTP client used to send the request. + */ + @Generated + private HttpClient httpClient; + + /** + * {@inheritDoc}. + */ + @Generated + @Override + public ArrayClientBuilder httpClient(HttpClient httpClient) { + this.httpClient = httpClient; + return this; + } + + /* + * The HTTP pipeline to send requests through. + */ + @Generated + private HttpPipeline pipeline; + + /** + * {@inheritDoc}. + */ + @Generated + @Override + public ArrayClientBuilder pipeline(HttpPipeline pipeline) { + if (this.pipeline != null && pipeline == null) { + LOGGER.atInfo().log("HttpPipeline is being set to 'null' when it was previously configured."); + } + this.pipeline = pipeline; + return this; + } + + /* + * The logging configuration for HTTP requests and responses. + */ + @Generated + private HttpLogOptions httpLogOptions; + + /** + * {@inheritDoc}. + */ + @Generated + @Override + public ArrayClientBuilder httpLogOptions(HttpLogOptions httpLogOptions) { + this.httpLogOptions = httpLogOptions; + return this; + } + + /* + * The client options such as application ID and custom headers to set on a request. + */ + @Generated + private ClientOptions clientOptions; + + /** + * {@inheritDoc}. + */ + @Generated + @Override + public ArrayClientBuilder clientOptions(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + return this; + } + + /* + * The retry options to configure retry policy for failed requests. + */ + @Generated + private RetryOptions retryOptions; + + /** + * {@inheritDoc}. + */ + @Generated + @Override + public ArrayClientBuilder retryOptions(RetryOptions retryOptions) { + this.retryOptions = retryOptions; + return this; + } + + /** + * {@inheritDoc}. + */ + @Generated + @Override + public ArrayClientBuilder addPolicy(HttpPipelinePolicy customPolicy) { + Objects.requireNonNull(customPolicy, "'customPolicy' cannot be null."); + pipelinePolicies.add(customPolicy); + return this; + } + + /* + * The configuration store that is used during construction of the service client. + */ + @Generated + private Configuration configuration; + + /** + * {@inheritDoc}. + */ + @Generated + @Override + public ArrayClientBuilder configuration(Configuration configuration) { + this.configuration = configuration; + return this; + } + + /* + * The service endpoint + */ + @Generated + private String endpoint; + + /** + * {@inheritDoc}. + */ + @Generated + @Override + public ArrayClientBuilder endpoint(String endpoint) { + this.endpoint = endpoint; + return this; + } + + /* + * The retry policy that will attempt to retry failed requests, if applicable. + */ + @Generated + private RetryPolicy retryPolicy; + + /** + * Sets The retry policy that will attempt to retry failed requests, if applicable. + * + * @param retryPolicy the retryPolicy value. + * @return the ArrayClientBuilder. + */ + @Generated + public ArrayClientBuilder retryPolicy(RetryPolicy retryPolicy) { + this.retryPolicy = retryPolicy; + return this; + } + + /** + * Builds an instance of ArrayClientImpl with the provided parameters. + * + * @return an instance of ArrayClientImpl. + */ + @Generated + private ArrayClientImpl buildInnerClient() { + this.validateClient(); + HttpPipeline localPipeline = (pipeline != null) ? pipeline : createHttpPipeline(); + String localEndpoint = (endpoint != null) ? endpoint : "http://localhost:3000"; + ArrayClientImpl client + = new ArrayClientImpl(localPipeline, JacksonAdapter.createDefaultSerializerAdapter(), localEndpoint); + return client; + } + + @Generated + private void validateClient() { + // This method is invoked from 'buildInnerClient'/'buildClient' method. + // Developer can customize this method, to validate that the necessary conditions are met for the new client. + } + + @Generated + private HttpPipeline createHttpPipeline() { + Configuration buildConfiguration + = (configuration == null) ? Configuration.getGlobalConfiguration() : configuration; + HttpLogOptions localHttpLogOptions = this.httpLogOptions == null ? new HttpLogOptions() : this.httpLogOptions; + ClientOptions localClientOptions = this.clientOptions == null ? new ClientOptions() : this.clientOptions; + List policies = new ArrayList<>(); + String clientName = PROPERTIES.getOrDefault(SDK_NAME, "UnknownName"); + String clientVersion = PROPERTIES.getOrDefault(SDK_VERSION, "UnknownVersion"); + String applicationId = CoreUtils.getApplicationId(localClientOptions, localHttpLogOptions); + policies.add(new UserAgentPolicy(applicationId, clientName, clientVersion, buildConfiguration)); + policies.add(new RequestIdPolicy()); + policies.add(new AddHeadersFromContextPolicy()); + HttpHeaders headers = CoreUtils.createHttpHeadersFromClientOptions(localClientOptions); + if (headers != null) { + policies.add(new AddHeadersPolicy(headers)); + } + this.pipelinePolicies.stream() + .filter(p -> p.getPipelinePosition() == HttpPipelinePosition.PER_CALL) + .forEach(p -> policies.add(p)); + HttpPolicyProviders.addBeforeRetryPolicies(policies); + policies.add(ClientBuilderUtil.validateAndGetRetryPolicy(retryPolicy, retryOptions, new RetryPolicy())); + policies.add(new AddDatePolicy()); + this.pipelinePolicies.stream() + .filter(p -> p.getPipelinePosition() == HttpPipelinePosition.PER_RETRY) + .forEach(p -> policies.add(p)); + HttpPolicyProviders.addAfterRetryPolicies(policies); + policies.add(new HttpLoggingPolicy(localHttpLogOptions)); + HttpPipeline httpPipeline = new HttpPipelineBuilder().policies(policies.toArray(new HttpPipelinePolicy[0])) + .httpClient(httpClient) + .clientOptions(localClientOptions) + .build(); + return httpPipeline; + } + + /** + * Builds an instance of ArrayAsyncClient class. + * + * @return an instance of ArrayAsyncClient. + */ + @Generated + public ArrayAsyncClient buildAsyncClient() { + return new ArrayAsyncClient(buildInnerClient().getProperties()); + } + + /** + * Builds an instance of ArrayClient class. + * + * @return an instance of ArrayClient. + */ + @Generated + public ArrayClient buildClient() { + return new ArrayClient(buildInnerClient().getProperties()); + } + + private static final ClientLogger LOGGER = new ClientLogger(ArrayClientBuilder.class); +} diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/implementation/ArrayClientImpl.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/implementation/ArrayClientImpl.java new file mode 100644 index 00000000000..14b21d0341a --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/implementation/ArrayClientImpl.java @@ -0,0 +1,107 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package encode.array.implementation; + +import com.azure.core.http.HttpPipeline; +import com.azure.core.http.HttpPipelineBuilder; +import com.azure.core.http.policy.RetryPolicy; +import com.azure.core.http.policy.UserAgentPolicy; +import com.azure.core.util.serializer.JacksonAdapter; +import com.azure.core.util.serializer.SerializerAdapter; + +/** + * Initializes a new instance of the ArrayClient type. + */ +public final class ArrayClientImpl { + /** + * Service host. + */ + private final String endpoint; + + /** + * Gets Service host. + * + * @return the endpoint value. + */ + public String getEndpoint() { + return this.endpoint; + } + + /** + * The HTTP pipeline to send requests through. + */ + private final HttpPipeline httpPipeline; + + /** + * Gets The HTTP pipeline to send requests through. + * + * @return the httpPipeline value. + */ + public HttpPipeline getHttpPipeline() { + return this.httpPipeline; + } + + /** + * The serializer to serialize an object into a string. + */ + private final SerializerAdapter serializerAdapter; + + /** + * Gets The serializer to serialize an object into a string. + * + * @return the serializerAdapter value. + */ + public SerializerAdapter getSerializerAdapter() { + return this.serializerAdapter; + } + + /** + * The PropertiesImpl object to access its operations. + */ + private final PropertiesImpl properties; + + /** + * Gets the PropertiesImpl object to access its operations. + * + * @return the PropertiesImpl object. + */ + public PropertiesImpl getProperties() { + return this.properties; + } + + /** + * Initializes an instance of ArrayClient client. + * + * @param endpoint Service host. + */ + public ArrayClientImpl(String endpoint) { + this(new HttpPipelineBuilder().policies(new UserAgentPolicy(), new RetryPolicy()).build(), + JacksonAdapter.createDefaultSerializerAdapter(), endpoint); + } + + /** + * Initializes an instance of ArrayClient client. + * + * @param httpPipeline The HTTP pipeline to send requests through. + * @param endpoint Service host. + */ + public ArrayClientImpl(HttpPipeline httpPipeline, String endpoint) { + this(httpPipeline, JacksonAdapter.createDefaultSerializerAdapter(), endpoint); + } + + /** + * Initializes an instance of ArrayClient client. + * + * @param httpPipeline The HTTP pipeline to send requests through. + * @param serializerAdapter The serializer to serialize an object into a string. + * @param endpoint Service host. + */ + public ArrayClientImpl(HttpPipeline httpPipeline, SerializerAdapter serializerAdapter, String endpoint) { + this.httpPipeline = httpPipeline; + this.serializerAdapter = serializerAdapter; + this.endpoint = endpoint; + this.properties = new PropertiesImpl(this); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/implementation/PropertiesImpl.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/implementation/PropertiesImpl.java new file mode 100644 index 00000000000..ee142d68512 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/implementation/PropertiesImpl.java @@ -0,0 +1,478 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package encode.array.implementation; + +import com.azure.core.annotation.BodyParam; +import com.azure.core.annotation.ExpectedResponses; +import com.azure.core.annotation.HeaderParam; +import com.azure.core.annotation.Host; +import com.azure.core.annotation.HostParam; +import com.azure.core.annotation.Post; +import com.azure.core.annotation.ReturnType; +import com.azure.core.annotation.ServiceInterface; +import com.azure.core.annotation.ServiceMethod; +import com.azure.core.annotation.UnexpectedResponseExceptionType; +import com.azure.core.exception.ClientAuthenticationException; +import com.azure.core.exception.HttpResponseException; +import com.azure.core.exception.ResourceModifiedException; +import com.azure.core.exception.ResourceNotFoundException; +import com.azure.core.http.rest.RequestOptions; +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.RestProxy; +import com.azure.core.util.BinaryData; +import com.azure.core.util.Context; +import com.azure.core.util.FluxUtil; +import reactor.core.publisher.Mono; + +/** + * An instance of this class provides access to all the operations defined in Properties. + */ +public final class PropertiesImpl { + /** + * The proxy service used to perform REST calls. + */ + private final PropertiesService service; + + /** + * The service client containing this operation class. + */ + private final ArrayClientImpl client; + + /** + * Initializes an instance of PropertiesImpl. + * + * @param client the instance of the service client containing this operation class. + */ + PropertiesImpl(ArrayClientImpl client) { + this.service + = RestProxy.create(PropertiesService.class, client.getHttpPipeline(), client.getSerializerAdapter()); + this.client = client; + } + + /** + * The interface defining all the services for ArrayClientProperties to be used by the proxy service to perform REST + * calls. + */ + @Host("{endpoint}") + @ServiceInterface(name = "ArrayClientProperties") + public interface PropertiesService { + @Post("/encode/array/property/comma-delimited") + @ExpectedResponses({ 200 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> commaDelimited(@HostParam("endpoint") String endpoint, + @HeaderParam("Content-Type") String contentType, @HeaderParam("Accept") String accept, + @BodyParam("application/json") BinaryData body, RequestOptions requestOptions, Context context); + + @Post("/encode/array/property/comma-delimited") + @ExpectedResponses({ 200 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Response commaDelimitedSync(@HostParam("endpoint") String endpoint, + @HeaderParam("Content-Type") String contentType, @HeaderParam("Accept") String accept, + @BodyParam("application/json") BinaryData body, RequestOptions requestOptions, Context context); + + @Post("/encode/array/property/space-delimited") + @ExpectedResponses({ 200 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> spaceDelimited(@HostParam("endpoint") String endpoint, + @HeaderParam("Content-Type") String contentType, @HeaderParam("Accept") String accept, + @BodyParam("application/json") BinaryData body, RequestOptions requestOptions, Context context); + + @Post("/encode/array/property/space-delimited") + @ExpectedResponses({ 200 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Response spaceDelimitedSync(@HostParam("endpoint") String endpoint, + @HeaderParam("Content-Type") String contentType, @HeaderParam("Accept") String accept, + @BodyParam("application/json") BinaryData body, RequestOptions requestOptions, Context context); + + @Post("/encode/array/property/pipe-delimited") + @ExpectedResponses({ 200 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> pipeDelimited(@HostParam("endpoint") String endpoint, + @HeaderParam("Content-Type") String contentType, @HeaderParam("Accept") String accept, + @BodyParam("application/json") BinaryData body, RequestOptions requestOptions, Context context); + + @Post("/encode/array/property/pipe-delimited") + @ExpectedResponses({ 200 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Response pipeDelimitedSync(@HostParam("endpoint") String endpoint, + @HeaderParam("Content-Type") String contentType, @HeaderParam("Accept") String accept, + @BodyParam("application/json") BinaryData body, RequestOptions requestOptions, Context context); + + @Post("/encode/array/property/newline-delimited") + @ExpectedResponses({ 200 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> newlineDelimited(@HostParam("endpoint") String endpoint, + @HeaderParam("Content-Type") String contentType, @HeaderParam("Accept") String accept, + @BodyParam("application/json") BinaryData body, RequestOptions requestOptions, Context context); + + @Post("/encode/array/property/newline-delimited") + @ExpectedResponses({ 200 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Response newlineDelimitedSync(@HostParam("endpoint") String endpoint, + @HeaderParam("Content-Type") String contentType, @HeaderParam("Accept") String accept, + @BodyParam("application/json") BinaryData body, RequestOptions requestOptions, Context context); + } + + /** + * The commaDelimited operation. + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     value (Required): [
+     *         String (Required)
+     *     ]
+     * }
+     * }
+     * 
+ * + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     value (Required): [
+     *         String (Required)
+     *     ]
+     * }
+     * }
+     * 
+ * + * @param body The body parameter. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the response body along with {@link Response} on successful completion of {@link Mono}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> commaDelimitedWithResponseAsync(BinaryData body, RequestOptions requestOptions) { + final String contentType = "application/json"; + final String accept = "application/json"; + return FluxUtil.withContext(context -> service.commaDelimited(this.client.getEndpoint(), contentType, accept, + body, requestOptions, context)); + } + + /** + * The commaDelimited operation. + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     value (Required): [
+     *         String (Required)
+     *     ]
+     * }
+     * }
+     * 
+ * + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     value (Required): [
+     *         String (Required)
+     *     ]
+     * }
+     * }
+     * 
+ * + * @param body The body parameter. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the response body along with {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response commaDelimitedWithResponse(BinaryData body, RequestOptions requestOptions) { + final String contentType = "application/json"; + final String accept = "application/json"; + return service.commaDelimitedSync(this.client.getEndpoint(), contentType, accept, body, requestOptions, + Context.NONE); + } + + /** + * The spaceDelimited operation. + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     value (Required): [
+     *         String (Required)
+     *     ]
+     * }
+     * }
+     * 
+ * + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     value (Required): [
+     *         String (Required)
+     *     ]
+     * }
+     * }
+     * 
+ * + * @param body The body parameter. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the response body along with {@link Response} on successful completion of {@link Mono}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> spaceDelimitedWithResponseAsync(BinaryData body, RequestOptions requestOptions) { + final String contentType = "application/json"; + final String accept = "application/json"; + return FluxUtil.withContext(context -> service.spaceDelimited(this.client.getEndpoint(), contentType, accept, + body, requestOptions, context)); + } + + /** + * The spaceDelimited operation. + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     value (Required): [
+     *         String (Required)
+     *     ]
+     * }
+     * }
+     * 
+ * + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     value (Required): [
+     *         String (Required)
+     *     ]
+     * }
+     * }
+     * 
+ * + * @param body The body parameter. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the response body along with {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response spaceDelimitedWithResponse(BinaryData body, RequestOptions requestOptions) { + final String contentType = "application/json"; + final String accept = "application/json"; + return service.spaceDelimitedSync(this.client.getEndpoint(), contentType, accept, body, requestOptions, + Context.NONE); + } + + /** + * The pipeDelimited operation. + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     value (Required): [
+     *         String (Required)
+     *     ]
+     * }
+     * }
+     * 
+ * + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     value (Required): [
+     *         String (Required)
+     *     ]
+     * }
+     * }
+     * 
+ * + * @param body The body parameter. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the response body along with {@link Response} on successful completion of {@link Mono}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> pipeDelimitedWithResponseAsync(BinaryData body, RequestOptions requestOptions) { + final String contentType = "application/json"; + final String accept = "application/json"; + return FluxUtil.withContext(context -> service.pipeDelimited(this.client.getEndpoint(), contentType, accept, + body, requestOptions, context)); + } + + /** + * The pipeDelimited operation. + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     value (Required): [
+     *         String (Required)
+     *     ]
+     * }
+     * }
+     * 
+ * + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     value (Required): [
+     *         String (Required)
+     *     ]
+     * }
+     * }
+     * 
+ * + * @param body The body parameter. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the response body along with {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response pipeDelimitedWithResponse(BinaryData body, RequestOptions requestOptions) { + final String contentType = "application/json"; + final String accept = "application/json"; + return service.pipeDelimitedSync(this.client.getEndpoint(), contentType, accept, body, requestOptions, + Context.NONE); + } + + /** + * The newlineDelimited operation. + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     value (Required): [
+     *         String (Required)
+     *     ]
+     * }
+     * }
+     * 
+ * + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     value (Required): [
+     *         String (Required)
+     *     ]
+     * }
+     * }
+     * 
+ * + * @param body The body parameter. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the response body along with {@link Response} on successful completion of {@link Mono}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> newlineDelimitedWithResponseAsync(BinaryData body, + RequestOptions requestOptions) { + final String contentType = "application/json"; + final String accept = "application/json"; + return FluxUtil.withContext(context -> service.newlineDelimited(this.client.getEndpoint(), contentType, accept, + body, requestOptions, context)); + } + + /** + * The newlineDelimited operation. + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     value (Required): [
+     *         String (Required)
+     *     ]
+     * }
+     * }
+     * 
+ * + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     value (Required): [
+     *         String (Required)
+     *     ]
+     * }
+     * }
+     * 
+ * + * @param body The body parameter. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the response body along with {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response newlineDelimitedWithResponse(BinaryData body, RequestOptions requestOptions) { + final String contentType = "application/json"; + final String accept = "application/json"; + return service.newlineDelimitedSync(this.client.getEndpoint(), contentType, accept, body, requestOptions, + Context.NONE); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/implementation/package-info.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/implementation/package-info.java new file mode 100644 index 00000000000..57c9ca5eac9 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/implementation/package-info.java @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +/** + * + * Package containing the implementations for Array. + * Test for encode decorator on array. + * + */ +package encode.array.implementation; diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/models/CommaDelimitedArrayProperty.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/models/CommaDelimitedArrayProperty.java new file mode 100644 index 00000000000..1e3a6406b61 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/models/CommaDelimitedArrayProperty.java @@ -0,0 +1,84 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package encode.array.models; + +import com.azure.core.annotation.Generated; +import com.azure.core.annotation.Immutable; +import com.azure.json.JsonReader; +import com.azure.json.JsonSerializable; +import com.azure.json.JsonToken; +import com.azure.json.JsonWriter; +import java.io.IOException; +import java.util.List; + +/** + * The CommaDelimitedArrayProperty model. + */ +@Immutable +public final class CommaDelimitedArrayProperty implements JsonSerializable { + /* + * The value property. + */ + @Generated + private final List value; + + /** + * Creates an instance of CommaDelimitedArrayProperty class. + * + * @param value the value value to set. + */ + @Generated + public CommaDelimitedArrayProperty(List value) { + this.value = value; + } + + /** + * Get the value property: The value property. + * + * @return the value value. + */ + @Generated + public List getValue() { + return this.value; + } + + /** + * {@inheritDoc} + */ + @Generated + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + jsonWriter.writeArrayField("value", this.value, (writer, element) -> writer.writeString(element)); + return jsonWriter.writeEndObject(); + } + + /** + * Reads an instance of CommaDelimitedArrayProperty from the JsonReader. + * + * @param jsonReader The JsonReader being read. + * @return An instance of CommaDelimitedArrayProperty if the JsonReader was pointing to an instance of it, or null + * if it was pointing to JSON null. + * @throws IllegalStateException If the deserialized JSON object was missing any required properties. + * @throws IOException If an error occurs while reading the CommaDelimitedArrayProperty. + */ + @Generated + public static CommaDelimitedArrayProperty fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject(reader -> { + List value = null; + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("value".equals(fieldName)) { + value = reader.readArray(reader1 -> reader1.getString()); + } else { + reader.skipChildren(); + } + } + return new CommaDelimitedArrayProperty(value); + }); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/models/NewlineDelimitedArrayProperty.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/models/NewlineDelimitedArrayProperty.java new file mode 100644 index 00000000000..605c2f10f09 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/models/NewlineDelimitedArrayProperty.java @@ -0,0 +1,84 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package encode.array.models; + +import com.azure.core.annotation.Generated; +import com.azure.core.annotation.Immutable; +import com.azure.json.JsonReader; +import com.azure.json.JsonSerializable; +import com.azure.json.JsonToken; +import com.azure.json.JsonWriter; +import java.io.IOException; +import java.util.List; + +/** + * The NewlineDelimitedArrayProperty model. + */ +@Immutable +public final class NewlineDelimitedArrayProperty implements JsonSerializable { + /* + * The value property. + */ + @Generated + private final List value; + + /** + * Creates an instance of NewlineDelimitedArrayProperty class. + * + * @param value the value value to set. + */ + @Generated + public NewlineDelimitedArrayProperty(List value) { + this.value = value; + } + + /** + * Get the value property: The value property. + * + * @return the value value. + */ + @Generated + public List getValue() { + return this.value; + } + + /** + * {@inheritDoc} + */ + @Generated + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + jsonWriter.writeArrayField("value", this.value, (writer, element) -> writer.writeString(element)); + return jsonWriter.writeEndObject(); + } + + /** + * Reads an instance of NewlineDelimitedArrayProperty from the JsonReader. + * + * @param jsonReader The JsonReader being read. + * @return An instance of NewlineDelimitedArrayProperty if the JsonReader was pointing to an instance of it, or null + * if it was pointing to JSON null. + * @throws IllegalStateException If the deserialized JSON object was missing any required properties. + * @throws IOException If an error occurs while reading the NewlineDelimitedArrayProperty. + */ + @Generated + public static NewlineDelimitedArrayProperty fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject(reader -> { + List value = null; + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("value".equals(fieldName)) { + value = reader.readArray(reader1 -> reader1.getString()); + } else { + reader.skipChildren(); + } + } + return new NewlineDelimitedArrayProperty(value); + }); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/models/PipeDelimitedArrayProperty.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/models/PipeDelimitedArrayProperty.java new file mode 100644 index 00000000000..6f9b85082c1 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/models/PipeDelimitedArrayProperty.java @@ -0,0 +1,84 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package encode.array.models; + +import com.azure.core.annotation.Generated; +import com.azure.core.annotation.Immutable; +import com.azure.json.JsonReader; +import com.azure.json.JsonSerializable; +import com.azure.json.JsonToken; +import com.azure.json.JsonWriter; +import java.io.IOException; +import java.util.List; + +/** + * The PipeDelimitedArrayProperty model. + */ +@Immutable +public final class PipeDelimitedArrayProperty implements JsonSerializable { + /* + * The value property. + */ + @Generated + private final List value; + + /** + * Creates an instance of PipeDelimitedArrayProperty class. + * + * @param value the value value to set. + */ + @Generated + public PipeDelimitedArrayProperty(List value) { + this.value = value; + } + + /** + * Get the value property: The value property. + * + * @return the value value. + */ + @Generated + public List getValue() { + return this.value; + } + + /** + * {@inheritDoc} + */ + @Generated + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + jsonWriter.writeArrayField("value", this.value, (writer, element) -> writer.writeString(element)); + return jsonWriter.writeEndObject(); + } + + /** + * Reads an instance of PipeDelimitedArrayProperty from the JsonReader. + * + * @param jsonReader The JsonReader being read. + * @return An instance of PipeDelimitedArrayProperty if the JsonReader was pointing to an instance of it, or null if + * it was pointing to JSON null. + * @throws IllegalStateException If the deserialized JSON object was missing any required properties. + * @throws IOException If an error occurs while reading the PipeDelimitedArrayProperty. + */ + @Generated + public static PipeDelimitedArrayProperty fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject(reader -> { + List value = null; + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("value".equals(fieldName)) { + value = reader.readArray(reader1 -> reader1.getString()); + } else { + reader.skipChildren(); + } + } + return new PipeDelimitedArrayProperty(value); + }); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/models/SpaceDelimitedArrayProperty.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/models/SpaceDelimitedArrayProperty.java new file mode 100644 index 00000000000..8a0d3181c2e --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/models/SpaceDelimitedArrayProperty.java @@ -0,0 +1,84 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package encode.array.models; + +import com.azure.core.annotation.Generated; +import com.azure.core.annotation.Immutable; +import com.azure.json.JsonReader; +import com.azure.json.JsonSerializable; +import com.azure.json.JsonToken; +import com.azure.json.JsonWriter; +import java.io.IOException; +import java.util.List; + +/** + * The SpaceDelimitedArrayProperty model. + */ +@Immutable +public final class SpaceDelimitedArrayProperty implements JsonSerializable { + /* + * The value property. + */ + @Generated + private final List value; + + /** + * Creates an instance of SpaceDelimitedArrayProperty class. + * + * @param value the value value to set. + */ + @Generated + public SpaceDelimitedArrayProperty(List value) { + this.value = value; + } + + /** + * Get the value property: The value property. + * + * @return the value value. + */ + @Generated + public List getValue() { + return this.value; + } + + /** + * {@inheritDoc} + */ + @Generated + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + jsonWriter.writeArrayField("value", this.value, (writer, element) -> writer.writeString(element)); + return jsonWriter.writeEndObject(); + } + + /** + * Reads an instance of SpaceDelimitedArrayProperty from the JsonReader. + * + * @param jsonReader The JsonReader being read. + * @return An instance of SpaceDelimitedArrayProperty if the JsonReader was pointing to an instance of it, or null + * if it was pointing to JSON null. + * @throws IllegalStateException If the deserialized JSON object was missing any required properties. + * @throws IOException If an error occurs while reading the SpaceDelimitedArrayProperty. + */ + @Generated + public static SpaceDelimitedArrayProperty fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject(reader -> { + List value = null; + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("value".equals(fieldName)) { + value = reader.readArray(reader1 -> reader1.getString()); + } else { + reader.skipChildren(); + } + } + return new SpaceDelimitedArrayProperty(value); + }); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/models/package-info.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/models/package-info.java new file mode 100644 index 00000000000..7db692b7214 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/models/package-info.java @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +/** + * + * Package containing the data models for Array. + * Test for encode decorator on array. + * + */ +package encode.array.models; diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/package-info.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/package-info.java new file mode 100644 index 00000000000..0167f7cae0c --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/encode/array/package-info.java @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +/** + * + * Package containing the classes for Array. + * Test for encode decorator on array. + * + */ +package encode.array; diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/specialwords/ModelPropertiesAsyncClient.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/specialwords/ModelPropertiesAsyncClient.java index 52defbfeae1..e8922e855b9 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/specialwords/ModelPropertiesAsyncClient.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/specialwords/ModelPropertiesAsyncClient.java @@ -18,6 +18,7 @@ import com.azure.core.util.FluxUtil; import reactor.core.publisher.Mono; import specialwords.implementation.ModelPropertiesImpl; +import specialwords.modelproperties.models.DictMethods; import specialwords.modelproperties.models.SameAsModel; /** @@ -64,6 +65,41 @@ public Mono> sameAsModelWithResponse(BinaryData body, RequestOpti return this.serviceClient.sameAsModelWithResponseAsync(body, requestOptions); } + /** + * The dictMethods operation. + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     keys: String (Required)
+     *     items: String (Required)
+     *     values: String (Required)
+     *     popitem: String (Required)
+     *     clear: String (Required)
+     *     update: String (Required)
+     *     setdefault: String (Required)
+     *     pop: String (Required)
+     *     get: String (Required)
+     *     copy: String (Required)
+     * }
+     * }
+     * 
+ * + * @param body The body parameter. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response} on successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> dictMethodsWithResponse(BinaryData body, RequestOptions requestOptions) { + return this.serviceClient.dictMethodsWithResponseAsync(body, requestOptions); + } + /** * The sameAsModel operation. * @@ -83,4 +119,24 @@ public Mono sameAsModel(SameAsModel body) { RequestOptions requestOptions = new RequestOptions(); return sameAsModelWithResponse(BinaryData.fromObject(body), requestOptions).flatMap(FluxUtil::toMono); } + + /** + * The dictMethods operation. + * + * @param body The body parameter. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return A {@link Mono} that completes when a successful response is received. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono dictMethods(DictMethods body) { + // Generated convenience method for dictMethodsWithResponse + RequestOptions requestOptions = new RequestOptions(); + return dictMethodsWithResponse(BinaryData.fromObject(body), requestOptions).flatMap(FluxUtil::toMono); + } } diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/specialwords/ModelPropertiesClient.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/specialwords/ModelPropertiesClient.java index 29314fdb99e..1374bc9f693 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/specialwords/ModelPropertiesClient.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/specialwords/ModelPropertiesClient.java @@ -16,6 +16,7 @@ import com.azure.core.http.rest.Response; import com.azure.core.util.BinaryData; import specialwords.implementation.ModelPropertiesImpl; +import specialwords.modelproperties.models.DictMethods; import specialwords.modelproperties.models.SameAsModel; /** @@ -62,6 +63,41 @@ public Response sameAsModelWithResponse(BinaryData body, RequestOptions re return this.serviceClient.sameAsModelWithResponse(body, requestOptions); } + /** + * The dictMethods operation. + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     keys: String (Required)
+     *     items: String (Required)
+     *     values: String (Required)
+     *     popitem: String (Required)
+     *     clear: String (Required)
+     *     update: String (Required)
+     *     setdefault: String (Required)
+     *     pop: String (Required)
+     *     get: String (Required)
+     *     copy: String (Required)
+     * }
+     * }
+     * 
+ * + * @param body The body parameter. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Response dictMethodsWithResponse(BinaryData body, RequestOptions requestOptions) { + return this.serviceClient.dictMethodsWithResponse(body, requestOptions); + } + /** * The sameAsModel operation. * @@ -80,4 +116,23 @@ public void sameAsModel(SameAsModel body) { RequestOptions requestOptions = new RequestOptions(); sameAsModelWithResponse(BinaryData.fromObject(body), requestOptions).getValue(); } + + /** + * The dictMethods operation. + * + * @param body The body parameter. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public void dictMethods(DictMethods body) { + // Generated convenience method for dictMethodsWithResponse + RequestOptions requestOptions = new RequestOptions(); + dictMethodsWithResponse(BinaryData.fromObject(body), requestOptions).getValue(); + } } diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/specialwords/implementation/ModelPropertiesImpl.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/specialwords/implementation/ModelPropertiesImpl.java index 0967331146a..f8d2e28261c 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/java/specialwords/implementation/ModelPropertiesImpl.java +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/specialwords/implementation/ModelPropertiesImpl.java @@ -77,6 +77,26 @@ Mono> sameAsModel(@HostParam("endpoint") String endpoint, Response sameAsModelSync(@HostParam("endpoint") String endpoint, @HeaderParam("Content-Type") String contentType, @BodyParam("application/json") BinaryData body, RequestOptions requestOptions, Context context); + + @Post("/special-words/model-properties/dict-methods") + @ExpectedResponses({ 204 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> dictMethods(@HostParam("endpoint") String endpoint, + @HeaderParam("Content-Type") String contentType, @BodyParam("application/json") BinaryData body, + RequestOptions requestOptions, Context context); + + @Post("/special-words/model-properties/dict-methods") + @ExpectedResponses({ 204 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Response dictMethodsSync(@HostParam("endpoint") String endpoint, + @HeaderParam("Content-Type") String contentType, @BodyParam("application/json") BinaryData body, + RequestOptions requestOptions, Context context); } /** @@ -131,4 +151,75 @@ public Response sameAsModelWithResponse(BinaryData body, RequestOptions re final String contentType = "application/json"; return service.sameAsModelSync(this.client.getEndpoint(), contentType, body, requestOptions, Context.NONE); } + + /** + * The dictMethods operation. + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     keys: String (Required)
+     *     items: String (Required)
+     *     values: String (Required)
+     *     popitem: String (Required)
+     *     clear: String (Required)
+     *     update: String (Required)
+     *     setdefault: String (Required)
+     *     pop: String (Required)
+     *     get: String (Required)
+     *     copy: String (Required)
+     * }
+     * }
+     * 
+ * + * @param body The body parameter. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response} on successful completion of {@link Mono}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> dictMethodsWithResponseAsync(BinaryData body, RequestOptions requestOptions) { + final String contentType = "application/json"; + return FluxUtil.withContext( + context -> service.dictMethods(this.client.getEndpoint(), contentType, body, requestOptions, context)); + } + + /** + * The dictMethods operation. + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     keys: String (Required)
+     *     items: String (Required)
+     *     values: String (Required)
+     *     popitem: String (Required)
+     *     clear: String (Required)
+     *     update: String (Required)
+     *     setdefault: String (Required)
+     *     pop: String (Required)
+     *     get: String (Required)
+     *     copy: String (Required)
+     * }
+     * }
+     * 
+ * + * @param body The body parameter. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response dictMethodsWithResponse(BinaryData body, RequestOptions requestOptions) { + final String contentType = "application/json"; + return service.dictMethodsSync(this.client.getEndpoint(), contentType, body, requestOptions, Context.NONE); + } } diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/java/specialwords/modelproperties/models/DictMethods.java b/packages/http-client-java/generator/http-client-generator-test/src/main/java/specialwords/modelproperties/models/DictMethods.java new file mode 100644 index 00000000000..fd5b55c5f65 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/java/specialwords/modelproperties/models/DictMethods.java @@ -0,0 +1,282 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package specialwords.modelproperties.models; + +import com.azure.core.annotation.Generated; +import com.azure.core.annotation.Immutable; +import com.azure.json.JsonReader; +import com.azure.json.JsonSerializable; +import com.azure.json.JsonToken; +import com.azure.json.JsonWriter; +import java.io.IOException; + +/** + * The DictMethods model. + */ +@Immutable +public final class DictMethods implements JsonSerializable { + /* + * The keys property. + */ + @Generated + private final String keys; + + /* + * The items property. + */ + @Generated + private final String items; + + /* + * The values property. + */ + @Generated + private final String values; + + /* + * The popitem property. + */ + @Generated + private final String popitem; + + /* + * The clear property. + */ + @Generated + private final String clear; + + /* + * The update property. + */ + @Generated + private final String update; + + /* + * The setdefault property. + */ + @Generated + private final String setdefault; + + /* + * The pop property. + */ + @Generated + private final String pop; + + /* + * The get property. + */ + @Generated + private final String get; + + /* + * The copy property. + */ + @Generated + private final String copy; + + /** + * Creates an instance of DictMethods class. + * + * @param keys the keys value to set. + * @param items the items value to set. + * @param values the values value to set. + * @param popitem the popitem value to set. + * @param clear the clear value to set. + * @param update the update value to set. + * @param setdefault the setdefault value to set. + * @param pop the pop value to set. + * @param get the get value to set. + * @param copy the copy value to set. + */ + @Generated + public DictMethods(String keys, String items, String values, String popitem, String clear, String update, + String setdefault, String pop, String get, String copy) { + this.keys = keys; + this.items = items; + this.values = values; + this.popitem = popitem; + this.clear = clear; + this.update = update; + this.setdefault = setdefault; + this.pop = pop; + this.get = get; + this.copy = copy; + } + + /** + * Get the keys property: The keys property. + * + * @return the keys value. + */ + @Generated + public String getKeys() { + return this.keys; + } + + /** + * Get the items property: The items property. + * + * @return the items value. + */ + @Generated + public String getItems() { + return this.items; + } + + /** + * Get the values property: The values property. + * + * @return the values value. + */ + @Generated + public String getValues() { + return this.values; + } + + /** + * Get the popitem property: The popitem property. + * + * @return the popitem value. + */ + @Generated + public String getPopitem() { + return this.popitem; + } + + /** + * Get the clear property: The clear property. + * + * @return the clear value. + */ + @Generated + public String getClear() { + return this.clear; + } + + /** + * Get the update property: The update property. + * + * @return the update value. + */ + @Generated + public String getUpdate() { + return this.update; + } + + /** + * Get the setdefault property: The setdefault property. + * + * @return the setdefault value. + */ + @Generated + public String getSetdefault() { + return this.setdefault; + } + + /** + * Get the pop property: The pop property. + * + * @return the pop value. + */ + @Generated + public String getPop() { + return this.pop; + } + + /** + * Get the get property: The get property. + * + * @return the get value. + */ + @Generated + public String getGet() { + return this.get; + } + + /** + * Get the copy property: The copy property. + * + * @return the copy value. + */ + @Generated + public String getCopy() { + return this.copy; + } + + /** + * {@inheritDoc} + */ + @Generated + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + jsonWriter.writeStringField("keys", this.keys); + jsonWriter.writeStringField("items", this.items); + jsonWriter.writeStringField("values", this.values); + jsonWriter.writeStringField("popitem", this.popitem); + jsonWriter.writeStringField("clear", this.clear); + jsonWriter.writeStringField("update", this.update); + jsonWriter.writeStringField("setdefault", this.setdefault); + jsonWriter.writeStringField("pop", this.pop); + jsonWriter.writeStringField("get", this.get); + jsonWriter.writeStringField("copy", this.copy); + return jsonWriter.writeEndObject(); + } + + /** + * Reads an instance of DictMethods from the JsonReader. + * + * @param jsonReader The JsonReader being read. + * @return An instance of DictMethods if the JsonReader was pointing to an instance of it, or null if it was + * pointing to JSON null. + * @throws IllegalStateException If the deserialized JSON object was missing any required properties. + * @throws IOException If an error occurs while reading the DictMethods. + */ + @Generated + public static DictMethods fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject(reader -> { + String keys = null; + String items = null; + String values = null; + String popitem = null; + String clear = null; + String update = null; + String setdefault = null; + String pop = null; + String get = null; + String copy = null; + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("keys".equals(fieldName)) { + keys = reader.getString(); + } else if ("items".equals(fieldName)) { + items = reader.getString(); + } else if ("values".equals(fieldName)) { + values = reader.getString(); + } else if ("popitem".equals(fieldName)) { + popitem = reader.getString(); + } else if ("clear".equals(fieldName)) { + clear = reader.getString(); + } else if ("update".equals(fieldName)) { + update = reader.getString(); + } else if ("setdefault".equals(fieldName)) { + setdefault = reader.getString(); + } else if ("pop".equals(fieldName)) { + pop = reader.getString(); + } else if ("get".equals(fieldName)) { + get = reader.getString(); + } else if ("copy".equals(fieldName)) { + copy = reader.getString(); + } else { + reader.skipChildren(); + } + } + return new DictMethods(keys, items, values, popitem, clear, update, setdefault, pop, get, copy); + }); + } +} diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/azure-clientgenerator-core-clientinitialization_apiview_properties.json b/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/azure-clientgenerator-core-clientinitialization_apiview_properties.json index c14dc0e9935..c7da87b4bf0 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/azure-clientgenerator-core-clientinitialization_apiview_properties.json +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/azure-clientgenerator-core-clientinitialization_apiview_properties.json @@ -1,85 +1,85 @@ { "flavor": "Azure", "CrossLanguageDefinitionId": { - "azure.clientgenerator.core.clientinitialization.HeaderParamAsyncClient": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.HeaderParam", - "azure.clientgenerator.core.clientinitialization.HeaderParamAsyncClient.withBody": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.HeaderParam.withBody", - "azure.clientgenerator.core.clientinitialization.HeaderParamAsyncClient.withBodyWithResponse": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.HeaderParam.withBody", - "azure.clientgenerator.core.clientinitialization.HeaderParamAsyncClient.withQuery": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.HeaderParam.withQuery", - "azure.clientgenerator.core.clientinitialization.HeaderParamAsyncClient.withQueryWithResponse": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.HeaderParam.withQuery", - "azure.clientgenerator.core.clientinitialization.HeaderParamClient": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.HeaderParam", - "azure.clientgenerator.core.clientinitialization.HeaderParamClient.withBody": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.HeaderParam.withBody", - "azure.clientgenerator.core.clientinitialization.HeaderParamClient.withBodyWithResponse": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.HeaderParam.withBody", - "azure.clientgenerator.core.clientinitialization.HeaderParamClient.withQuery": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.HeaderParam.withQuery", - "azure.clientgenerator.core.clientinitialization.HeaderParamClient.withQueryWithResponse": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.HeaderParam.withQuery", - "azure.clientgenerator.core.clientinitialization.HeaderParamClientBuilder": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.HeaderParam", - "azure.clientgenerator.core.clientinitialization.MixedParamsAsyncClient": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MixedParams", - "azure.clientgenerator.core.clientinitialization.MixedParamsAsyncClient.withBody": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MixedParams.withBody", - "azure.clientgenerator.core.clientinitialization.MixedParamsAsyncClient.withBodyWithResponse": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MixedParams.withBody", - "azure.clientgenerator.core.clientinitialization.MixedParamsAsyncClient.withQuery": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MixedParams.withQuery", - "azure.clientgenerator.core.clientinitialization.MixedParamsAsyncClient.withQueryWithResponse": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MixedParams.withQuery", - "azure.clientgenerator.core.clientinitialization.MixedParamsClient": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MixedParams", - "azure.clientgenerator.core.clientinitialization.MixedParamsClient.withBody": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MixedParams.withBody", - "azure.clientgenerator.core.clientinitialization.MixedParamsClient.withBodyWithResponse": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MixedParams.withBody", - "azure.clientgenerator.core.clientinitialization.MixedParamsClient.withQuery": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MixedParams.withQuery", - "azure.clientgenerator.core.clientinitialization.MixedParamsClient.withQueryWithResponse": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MixedParams.withQuery", - "azure.clientgenerator.core.clientinitialization.MixedParamsClientBuilder": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MixedParams", - "azure.clientgenerator.core.clientinitialization.MultipleParamsAsyncClient": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MultipleParams", - "azure.clientgenerator.core.clientinitialization.MultipleParamsAsyncClient.withBody": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MultipleParams.withBody", - "azure.clientgenerator.core.clientinitialization.MultipleParamsAsyncClient.withBodyWithResponse": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MultipleParams.withBody", - "azure.clientgenerator.core.clientinitialization.MultipleParamsAsyncClient.withQuery": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MultipleParams.withQuery", - "azure.clientgenerator.core.clientinitialization.MultipleParamsAsyncClient.withQueryWithResponse": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MultipleParams.withQuery", - "azure.clientgenerator.core.clientinitialization.MultipleParamsClient": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MultipleParams", - "azure.clientgenerator.core.clientinitialization.MultipleParamsClient.withBody": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MultipleParams.withBody", - "azure.clientgenerator.core.clientinitialization.MultipleParamsClient.withBodyWithResponse": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MultipleParams.withBody", - "azure.clientgenerator.core.clientinitialization.MultipleParamsClient.withQuery": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MultipleParams.withQuery", - "azure.clientgenerator.core.clientinitialization.MultipleParamsClient.withQueryWithResponse": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MultipleParams.withQuery", - "azure.clientgenerator.core.clientinitialization.MultipleParamsClientBuilder": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MultipleParams", - "azure.clientgenerator.core.clientinitialization.ParamAliasAsyncClient": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParamAlias", - "azure.clientgenerator.core.clientinitialization.ParamAliasAsyncClient.withAliasedName": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParamAlias.withAliasedName", - "azure.clientgenerator.core.clientinitialization.ParamAliasAsyncClient.withAliasedNameWithResponse": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParamAlias.withAliasedName", - "azure.clientgenerator.core.clientinitialization.ParamAliasAsyncClient.withOriginalName": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParamAlias.withOriginalName", - "azure.clientgenerator.core.clientinitialization.ParamAliasAsyncClient.withOriginalNameWithResponse": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParamAlias.withOriginalName", - "azure.clientgenerator.core.clientinitialization.ParamAliasClient": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParamAlias", - "azure.clientgenerator.core.clientinitialization.ParamAliasClient.withAliasedName": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParamAlias.withAliasedName", - "azure.clientgenerator.core.clientinitialization.ParamAliasClient.withAliasedNameWithResponse": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParamAlias.withAliasedName", - "azure.clientgenerator.core.clientinitialization.ParamAliasClient.withOriginalName": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParamAlias.withOriginalName", - "azure.clientgenerator.core.clientinitialization.ParamAliasClient.withOriginalNameWithResponse": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParamAlias.withOriginalName", - "azure.clientgenerator.core.clientinitialization.ParamAliasClientBuilder": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParamAlias", - "azure.clientgenerator.core.clientinitialization.PathParamAsyncClient": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.PathParam", - "azure.clientgenerator.core.clientinitialization.PathParamAsyncClient.deleteStandalone": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.PathParam.deleteStandalone", - "azure.clientgenerator.core.clientinitialization.PathParamAsyncClient.deleteStandaloneWithResponse": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.PathParam.deleteStandalone", - "azure.clientgenerator.core.clientinitialization.PathParamAsyncClient.getStandalone": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.PathParam.getStandalone", - "azure.clientgenerator.core.clientinitialization.PathParamAsyncClient.getStandaloneWithResponse": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.PathParam.getStandalone", - "azure.clientgenerator.core.clientinitialization.PathParamAsyncClient.withQuery": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.PathParam.withQuery", - "azure.clientgenerator.core.clientinitialization.PathParamAsyncClient.withQueryWithResponse": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.PathParam.withQuery", - "azure.clientgenerator.core.clientinitialization.PathParamClient": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.PathParam", - "azure.clientgenerator.core.clientinitialization.PathParamClient.deleteStandalone": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.PathParam.deleteStandalone", - "azure.clientgenerator.core.clientinitialization.PathParamClient.deleteStandaloneWithResponse": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.PathParam.deleteStandalone", - "azure.clientgenerator.core.clientinitialization.PathParamClient.getStandalone": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.PathParam.getStandalone", - "azure.clientgenerator.core.clientinitialization.PathParamClient.getStandaloneWithResponse": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.PathParam.getStandalone", - "azure.clientgenerator.core.clientinitialization.PathParamClient.withQuery": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.PathParam.withQuery", - "azure.clientgenerator.core.clientinitialization.PathParamClient.withQueryWithResponse": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.PathParam.withQuery", - "azure.clientgenerator.core.clientinitialization.PathParamClientBuilder": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.PathParam", + "azure.clientgenerator.core.clientinitialization.HeaderParamAsyncClient": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.HeaderParam", + "azure.clientgenerator.core.clientinitialization.HeaderParamAsyncClient.withBody": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.HeaderParam.withBody", + "azure.clientgenerator.core.clientinitialization.HeaderParamAsyncClient.withBodyWithResponse": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.HeaderParam.withBody", + "azure.clientgenerator.core.clientinitialization.HeaderParamAsyncClient.withQuery": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.HeaderParam.withQuery", + "azure.clientgenerator.core.clientinitialization.HeaderParamAsyncClient.withQueryWithResponse": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.HeaderParam.withQuery", + "azure.clientgenerator.core.clientinitialization.HeaderParamClient": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.HeaderParam", + "azure.clientgenerator.core.clientinitialization.HeaderParamClient.withBody": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.HeaderParam.withBody", + "azure.clientgenerator.core.clientinitialization.HeaderParamClient.withBodyWithResponse": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.HeaderParam.withBody", + "azure.clientgenerator.core.clientinitialization.HeaderParamClient.withQuery": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.HeaderParam.withQuery", + "azure.clientgenerator.core.clientinitialization.HeaderParamClient.withQueryWithResponse": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.HeaderParam.withQuery", + "azure.clientgenerator.core.clientinitialization.HeaderParamClientBuilder": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.HeaderParam", + "azure.clientgenerator.core.clientinitialization.MixedParamsAsyncClient": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MixedParams", + "azure.clientgenerator.core.clientinitialization.MixedParamsAsyncClient.withBody": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MixedParams.withBody", + "azure.clientgenerator.core.clientinitialization.MixedParamsAsyncClient.withBodyWithResponse": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MixedParams.withBody", + "azure.clientgenerator.core.clientinitialization.MixedParamsAsyncClient.withQuery": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MixedParams.withQuery", + "azure.clientgenerator.core.clientinitialization.MixedParamsAsyncClient.withQueryWithResponse": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MixedParams.withQuery", + "azure.clientgenerator.core.clientinitialization.MixedParamsClient": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MixedParams", + "azure.clientgenerator.core.clientinitialization.MixedParamsClient.withBody": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MixedParams.withBody", + "azure.clientgenerator.core.clientinitialization.MixedParamsClient.withBodyWithResponse": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MixedParams.withBody", + "azure.clientgenerator.core.clientinitialization.MixedParamsClient.withQuery": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MixedParams.withQuery", + "azure.clientgenerator.core.clientinitialization.MixedParamsClient.withQueryWithResponse": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MixedParams.withQuery", + "azure.clientgenerator.core.clientinitialization.MixedParamsClientBuilder": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MixedParams", + "azure.clientgenerator.core.clientinitialization.MultipleParamsAsyncClient": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MultipleParams", + "azure.clientgenerator.core.clientinitialization.MultipleParamsAsyncClient.withBody": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MultipleParams.withBody", + "azure.clientgenerator.core.clientinitialization.MultipleParamsAsyncClient.withBodyWithResponse": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MultipleParams.withBody", + "azure.clientgenerator.core.clientinitialization.MultipleParamsAsyncClient.withQuery": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MultipleParams.withQuery", + "azure.clientgenerator.core.clientinitialization.MultipleParamsAsyncClient.withQueryWithResponse": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MultipleParams.withQuery", + "azure.clientgenerator.core.clientinitialization.MultipleParamsClient": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MultipleParams", + "azure.clientgenerator.core.clientinitialization.MultipleParamsClient.withBody": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MultipleParams.withBody", + "azure.clientgenerator.core.clientinitialization.MultipleParamsClient.withBodyWithResponse": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MultipleParams.withBody", + "azure.clientgenerator.core.clientinitialization.MultipleParamsClient.withQuery": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MultipleParams.withQuery", + "azure.clientgenerator.core.clientinitialization.MultipleParamsClient.withQueryWithResponse": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MultipleParams.withQuery", + "azure.clientgenerator.core.clientinitialization.MultipleParamsClientBuilder": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MultipleParams", + "azure.clientgenerator.core.clientinitialization.ParamAliasAsyncClient": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParamAlias", + "azure.clientgenerator.core.clientinitialization.ParamAliasAsyncClient.withAliasedName": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParamAlias.withAliasedName", + "azure.clientgenerator.core.clientinitialization.ParamAliasAsyncClient.withAliasedNameWithResponse": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParamAlias.withAliasedName", + "azure.clientgenerator.core.clientinitialization.ParamAliasAsyncClient.withOriginalName": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParamAlias.withOriginalName", + "azure.clientgenerator.core.clientinitialization.ParamAliasAsyncClient.withOriginalNameWithResponse": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParamAlias.withOriginalName", + "azure.clientgenerator.core.clientinitialization.ParamAliasClient": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParamAlias", + "azure.clientgenerator.core.clientinitialization.ParamAliasClient.withAliasedName": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParamAlias.withAliasedName", + "azure.clientgenerator.core.clientinitialization.ParamAliasClient.withAliasedNameWithResponse": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParamAlias.withAliasedName", + "azure.clientgenerator.core.clientinitialization.ParamAliasClient.withOriginalName": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParamAlias.withOriginalName", + "azure.clientgenerator.core.clientinitialization.ParamAliasClient.withOriginalNameWithResponse": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParamAlias.withOriginalName", + "azure.clientgenerator.core.clientinitialization.ParamAliasClientBuilder": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParamAlias", + "azure.clientgenerator.core.clientinitialization.PathParamAsyncClient": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.PathParam", + "azure.clientgenerator.core.clientinitialization.PathParamAsyncClient.deleteStandalone": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.PathParam.deleteStandalone", + "azure.clientgenerator.core.clientinitialization.PathParamAsyncClient.deleteStandaloneWithResponse": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.PathParam.deleteStandalone", + "azure.clientgenerator.core.clientinitialization.PathParamAsyncClient.getStandalone": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.PathParam.getStandalone", + "azure.clientgenerator.core.clientinitialization.PathParamAsyncClient.getStandaloneWithResponse": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.PathParam.getStandalone", + "azure.clientgenerator.core.clientinitialization.PathParamAsyncClient.withQuery": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.PathParam.withQuery", + "azure.clientgenerator.core.clientinitialization.PathParamAsyncClient.withQueryWithResponse": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.PathParam.withQuery", + "azure.clientgenerator.core.clientinitialization.PathParamClient": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.PathParam", + "azure.clientgenerator.core.clientinitialization.PathParamClient.deleteStandalone": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.PathParam.deleteStandalone", + "azure.clientgenerator.core.clientinitialization.PathParamClient.deleteStandaloneWithResponse": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.PathParam.deleteStandalone", + "azure.clientgenerator.core.clientinitialization.PathParamClient.getStandalone": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.PathParam.getStandalone", + "azure.clientgenerator.core.clientinitialization.PathParamClient.getStandaloneWithResponse": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.PathParam.getStandalone", + "azure.clientgenerator.core.clientinitialization.PathParamClient.withQuery": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.PathParam.withQuery", + "azure.clientgenerator.core.clientinitialization.PathParamClient.withQueryWithResponse": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.PathParam.withQuery", + "azure.clientgenerator.core.clientinitialization.PathParamClientBuilder": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.PathParam", "azure.clientgenerator.core.clientinitialization.models.BlobProperties": "Service.BlobProperties", "azure.clientgenerator.core.clientinitialization.models.Input": "Service.Input", - "azure.clientgenerator.core.clientinitialization.models.WithBodyRequest": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.withBody.Request.anonymous", - "azure.clientgenerator.core.clientinitialization.parentclient.ChildAsyncClient": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParentClient.ChildClient", - "azure.clientgenerator.core.clientinitialization.parentclient.ChildAsyncClient.deleteStandalone": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParentClient.ChildClient.deleteStandalone", - "azure.clientgenerator.core.clientinitialization.parentclient.ChildAsyncClient.deleteStandaloneWithResponse": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParentClient.ChildClient.deleteStandalone", - "azure.clientgenerator.core.clientinitialization.parentclient.ChildAsyncClient.getStandalone": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParentClient.ChildClient.getStandalone", - "azure.clientgenerator.core.clientinitialization.parentclient.ChildAsyncClient.getStandaloneWithResponse": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParentClient.ChildClient.getStandalone", - "azure.clientgenerator.core.clientinitialization.parentclient.ChildAsyncClient.withQuery": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParentClient.ChildClient.withQuery", - "azure.clientgenerator.core.clientinitialization.parentclient.ChildAsyncClient.withQueryWithResponse": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParentClient.ChildClient.withQuery", - "azure.clientgenerator.core.clientinitialization.parentclient.ChildClient": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParentClient.ChildClient", - "azure.clientgenerator.core.clientinitialization.parentclient.ChildClient.deleteStandalone": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParentClient.ChildClient.deleteStandalone", - "azure.clientgenerator.core.clientinitialization.parentclient.ChildClient.deleteStandaloneWithResponse": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParentClient.ChildClient.deleteStandalone", - "azure.clientgenerator.core.clientinitialization.parentclient.ChildClient.getStandalone": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParentClient.ChildClient.getStandalone", - "azure.clientgenerator.core.clientinitialization.parentclient.ChildClient.getStandaloneWithResponse": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParentClient.ChildClient.getStandalone", - "azure.clientgenerator.core.clientinitialization.parentclient.ChildClient.withQuery": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParentClient.ChildClient.withQuery", - "azure.clientgenerator.core.clientinitialization.parentclient.ChildClient.withQueryWithResponse": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParentClient.ChildClient.withQuery", - "azure.clientgenerator.core.clientinitialization.parentclient.ChildClientBuilder": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParentClient.ChildClient", - "azure.clientgenerator.core.clientinitialization.parentclient.ParentAsyncClient": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParentClient", - "azure.clientgenerator.core.clientinitialization.parentclient.ParentClient": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParentClient", - "azure.clientgenerator.core.clientinitialization.parentclient.ParentClientBuilder": "_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParentClient" + "azure.clientgenerator.core.clientinitialization.models.WithBodyRequest": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.withBody.Request.anonymous", + "azure.clientgenerator.core.clientinitialization.parentclient.ChildAsyncClient": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParentClient.ChildClient", + "azure.clientgenerator.core.clientinitialization.parentclient.ChildAsyncClient.deleteStandalone": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParentClient.ChildClient.deleteStandalone", + "azure.clientgenerator.core.clientinitialization.parentclient.ChildAsyncClient.deleteStandaloneWithResponse": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParentClient.ChildClient.deleteStandalone", + "azure.clientgenerator.core.clientinitialization.parentclient.ChildAsyncClient.getStandalone": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParentClient.ChildClient.getStandalone", + "azure.clientgenerator.core.clientinitialization.parentclient.ChildAsyncClient.getStandaloneWithResponse": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParentClient.ChildClient.getStandalone", + "azure.clientgenerator.core.clientinitialization.parentclient.ChildAsyncClient.withQuery": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParentClient.ChildClient.withQuery", + "azure.clientgenerator.core.clientinitialization.parentclient.ChildAsyncClient.withQueryWithResponse": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParentClient.ChildClient.withQuery", + "azure.clientgenerator.core.clientinitialization.parentclient.ChildClient": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParentClient.ChildClient", + "azure.clientgenerator.core.clientinitialization.parentclient.ChildClient.deleteStandalone": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParentClient.ChildClient.deleteStandalone", + "azure.clientgenerator.core.clientinitialization.parentclient.ChildClient.deleteStandaloneWithResponse": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParentClient.ChildClient.deleteStandalone", + "azure.clientgenerator.core.clientinitialization.parentclient.ChildClient.getStandalone": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParentClient.ChildClient.getStandalone", + "azure.clientgenerator.core.clientinitialization.parentclient.ChildClient.getStandaloneWithResponse": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParentClient.ChildClient.getStandalone", + "azure.clientgenerator.core.clientinitialization.parentclient.ChildClient.withQuery": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParentClient.ChildClient.withQuery", + "azure.clientgenerator.core.clientinitialization.parentclient.ChildClient.withQueryWithResponse": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParentClient.ChildClient.withQuery", + "azure.clientgenerator.core.clientinitialization.parentclient.ChildClientBuilder": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParentClient.ChildClient", + "azure.clientgenerator.core.clientinitialization.parentclient.ParentAsyncClient": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParentClient", + "azure.clientgenerator.core.clientinitialization.parentclient.ParentClient": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParentClient", + "azure.clientgenerator.core.clientinitialization.parentclient.ParentClientBuilder": "_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParentClient" } } diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/azure-clientgenerator-core-clientinitialization_metadata.json b/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/azure-clientgenerator-core-clientinitialization_metadata.json index ee82536275c..8b2cc8b5ed8 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/azure-clientgenerator-core-clientinitialization_metadata.json +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/azure-clientgenerator-core-clientinitialization_metadata.json @@ -1 +1 @@ -{"flavor":"Azure","crossLanguageDefinitions":{"azure.clientgenerator.core.clientinitialization.HeaderParamAsyncClient":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.HeaderParam","azure.clientgenerator.core.clientinitialization.HeaderParamAsyncClient.withBody":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.HeaderParam.withBody","azure.clientgenerator.core.clientinitialization.HeaderParamAsyncClient.withBodyWithResponse":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.HeaderParam.withBody","azure.clientgenerator.core.clientinitialization.HeaderParamAsyncClient.withQuery":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.HeaderParam.withQuery","azure.clientgenerator.core.clientinitialization.HeaderParamAsyncClient.withQueryWithResponse":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.HeaderParam.withQuery","azure.clientgenerator.core.clientinitialization.HeaderParamClient":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.HeaderParam","azure.clientgenerator.core.clientinitialization.HeaderParamClient.withBody":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.HeaderParam.withBody","azure.clientgenerator.core.clientinitialization.HeaderParamClient.withBodyWithResponse":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.HeaderParam.withBody","azure.clientgenerator.core.clientinitialization.HeaderParamClient.withQuery":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.HeaderParam.withQuery","azure.clientgenerator.core.clientinitialization.HeaderParamClient.withQueryWithResponse":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.HeaderParam.withQuery","azure.clientgenerator.core.clientinitialization.HeaderParamClientBuilder":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.HeaderParam","azure.clientgenerator.core.clientinitialization.MixedParamsAsyncClient":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MixedParams","azure.clientgenerator.core.clientinitialization.MixedParamsAsyncClient.withBody":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MixedParams.withBody","azure.clientgenerator.core.clientinitialization.MixedParamsAsyncClient.withBodyWithResponse":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MixedParams.withBody","azure.clientgenerator.core.clientinitialization.MixedParamsAsyncClient.withQuery":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MixedParams.withQuery","azure.clientgenerator.core.clientinitialization.MixedParamsAsyncClient.withQueryWithResponse":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MixedParams.withQuery","azure.clientgenerator.core.clientinitialization.MixedParamsClient":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MixedParams","azure.clientgenerator.core.clientinitialization.MixedParamsClient.withBody":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MixedParams.withBody","azure.clientgenerator.core.clientinitialization.MixedParamsClient.withBodyWithResponse":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MixedParams.withBody","azure.clientgenerator.core.clientinitialization.MixedParamsClient.withQuery":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MixedParams.withQuery","azure.clientgenerator.core.clientinitialization.MixedParamsClient.withQueryWithResponse":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MixedParams.withQuery","azure.clientgenerator.core.clientinitialization.MixedParamsClientBuilder":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MixedParams","azure.clientgenerator.core.clientinitialization.MultipleParamsAsyncClient":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MultipleParams","azure.clientgenerator.core.clientinitialization.MultipleParamsAsyncClient.withBody":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MultipleParams.withBody","azure.clientgenerator.core.clientinitialization.MultipleParamsAsyncClient.withBodyWithResponse":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MultipleParams.withBody","azure.clientgenerator.core.clientinitialization.MultipleParamsAsyncClient.withQuery":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MultipleParams.withQuery","azure.clientgenerator.core.clientinitialization.MultipleParamsAsyncClient.withQueryWithResponse":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MultipleParams.withQuery","azure.clientgenerator.core.clientinitialization.MultipleParamsClient":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MultipleParams","azure.clientgenerator.core.clientinitialization.MultipleParamsClient.withBody":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MultipleParams.withBody","azure.clientgenerator.core.clientinitialization.MultipleParamsClient.withBodyWithResponse":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MultipleParams.withBody","azure.clientgenerator.core.clientinitialization.MultipleParamsClient.withQuery":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MultipleParams.withQuery","azure.clientgenerator.core.clientinitialization.MultipleParamsClient.withQueryWithResponse":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MultipleParams.withQuery","azure.clientgenerator.core.clientinitialization.MultipleParamsClientBuilder":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.MultipleParams","azure.clientgenerator.core.clientinitialization.ParamAliasAsyncClient":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParamAlias","azure.clientgenerator.core.clientinitialization.ParamAliasAsyncClient.withAliasedName":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParamAlias.withAliasedName","azure.clientgenerator.core.clientinitialization.ParamAliasAsyncClient.withAliasedNameWithResponse":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParamAlias.withAliasedName","azure.clientgenerator.core.clientinitialization.ParamAliasAsyncClient.withOriginalName":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParamAlias.withOriginalName","azure.clientgenerator.core.clientinitialization.ParamAliasAsyncClient.withOriginalNameWithResponse":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParamAlias.withOriginalName","azure.clientgenerator.core.clientinitialization.ParamAliasClient":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParamAlias","azure.clientgenerator.core.clientinitialization.ParamAliasClient.withAliasedName":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParamAlias.withAliasedName","azure.clientgenerator.core.clientinitialization.ParamAliasClient.withAliasedNameWithResponse":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParamAlias.withAliasedName","azure.clientgenerator.core.clientinitialization.ParamAliasClient.withOriginalName":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParamAlias.withOriginalName","azure.clientgenerator.core.clientinitialization.ParamAliasClient.withOriginalNameWithResponse":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParamAlias.withOriginalName","azure.clientgenerator.core.clientinitialization.ParamAliasClientBuilder":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParamAlias","azure.clientgenerator.core.clientinitialization.PathParamAsyncClient":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.PathParam","azure.clientgenerator.core.clientinitialization.PathParamAsyncClient.deleteStandalone":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.PathParam.deleteStandalone","azure.clientgenerator.core.clientinitialization.PathParamAsyncClient.deleteStandaloneWithResponse":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.PathParam.deleteStandalone","azure.clientgenerator.core.clientinitialization.PathParamAsyncClient.getStandalone":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.PathParam.getStandalone","azure.clientgenerator.core.clientinitialization.PathParamAsyncClient.getStandaloneWithResponse":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.PathParam.getStandalone","azure.clientgenerator.core.clientinitialization.PathParamAsyncClient.withQuery":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.PathParam.withQuery","azure.clientgenerator.core.clientinitialization.PathParamAsyncClient.withQueryWithResponse":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.PathParam.withQuery","azure.clientgenerator.core.clientinitialization.PathParamClient":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.PathParam","azure.clientgenerator.core.clientinitialization.PathParamClient.deleteStandalone":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.PathParam.deleteStandalone","azure.clientgenerator.core.clientinitialization.PathParamClient.deleteStandaloneWithResponse":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.PathParam.deleteStandalone","azure.clientgenerator.core.clientinitialization.PathParamClient.getStandalone":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.PathParam.getStandalone","azure.clientgenerator.core.clientinitialization.PathParamClient.getStandaloneWithResponse":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.PathParam.getStandalone","azure.clientgenerator.core.clientinitialization.PathParamClient.withQuery":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.PathParam.withQuery","azure.clientgenerator.core.clientinitialization.PathParamClient.withQueryWithResponse":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.PathParam.withQuery","azure.clientgenerator.core.clientinitialization.PathParamClientBuilder":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.PathParam","azure.clientgenerator.core.clientinitialization.models.BlobProperties":"Service.BlobProperties","azure.clientgenerator.core.clientinitialization.models.Input":"Service.Input","azure.clientgenerator.core.clientinitialization.models.WithBodyRequest":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.withBody.Request.anonymous","azure.clientgenerator.core.clientinitialization.parentclient.ChildAsyncClient":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParentClient.ChildClient","azure.clientgenerator.core.clientinitialization.parentclient.ChildAsyncClient.deleteStandalone":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParentClient.ChildClient.deleteStandalone","azure.clientgenerator.core.clientinitialization.parentclient.ChildAsyncClient.deleteStandaloneWithResponse":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParentClient.ChildClient.deleteStandalone","azure.clientgenerator.core.clientinitialization.parentclient.ChildAsyncClient.getStandalone":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParentClient.ChildClient.getStandalone","azure.clientgenerator.core.clientinitialization.parentclient.ChildAsyncClient.getStandaloneWithResponse":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParentClient.ChildClient.getStandalone","azure.clientgenerator.core.clientinitialization.parentclient.ChildAsyncClient.withQuery":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParentClient.ChildClient.withQuery","azure.clientgenerator.core.clientinitialization.parentclient.ChildAsyncClient.withQueryWithResponse":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParentClient.ChildClient.withQuery","azure.clientgenerator.core.clientinitialization.parentclient.ChildClient":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParentClient.ChildClient","azure.clientgenerator.core.clientinitialization.parentclient.ChildClient.deleteStandalone":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParentClient.ChildClient.deleteStandalone","azure.clientgenerator.core.clientinitialization.parentclient.ChildClient.deleteStandaloneWithResponse":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParentClient.ChildClient.deleteStandalone","azure.clientgenerator.core.clientinitialization.parentclient.ChildClient.getStandalone":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParentClient.ChildClient.getStandalone","azure.clientgenerator.core.clientinitialization.parentclient.ChildClient.getStandaloneWithResponse":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParentClient.ChildClient.getStandalone","azure.clientgenerator.core.clientinitialization.parentclient.ChildClient.withQuery":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParentClient.ChildClient.withQuery","azure.clientgenerator.core.clientinitialization.parentclient.ChildClient.withQueryWithResponse":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParentClient.ChildClient.withQuery","azure.clientgenerator.core.clientinitialization.parentclient.ChildClientBuilder":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParentClient.ChildClient","azure.clientgenerator.core.clientinitialization.parentclient.ParentAsyncClient":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParentClient","azure.clientgenerator.core.clientinitialization.parentclient.ParentClient":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParentClient","azure.clientgenerator.core.clientinitialization.parentclient.ParentClientBuilder":"_Specs_.Azure.ClientGeneratorCore.ClientInitialization.ParentClient"},"generatedFiles":["src/main/java/azure/clientgenerator/core/clientinitialization/HeaderParamAsyncClient.java","src/main/java/azure/clientgenerator/core/clientinitialization/HeaderParamClient.java","src/main/java/azure/clientgenerator/core/clientinitialization/HeaderParamClientBuilder.java","src/main/java/azure/clientgenerator/core/clientinitialization/MixedParamsAsyncClient.java","src/main/java/azure/clientgenerator/core/clientinitialization/MixedParamsClient.java","src/main/java/azure/clientgenerator/core/clientinitialization/MixedParamsClientBuilder.java","src/main/java/azure/clientgenerator/core/clientinitialization/MultipleParamsAsyncClient.java","src/main/java/azure/clientgenerator/core/clientinitialization/MultipleParamsClient.java","src/main/java/azure/clientgenerator/core/clientinitialization/MultipleParamsClientBuilder.java","src/main/java/azure/clientgenerator/core/clientinitialization/ParamAliasAsyncClient.java","src/main/java/azure/clientgenerator/core/clientinitialization/ParamAliasClient.java","src/main/java/azure/clientgenerator/core/clientinitialization/ParamAliasClientBuilder.java","src/main/java/azure/clientgenerator/core/clientinitialization/PathParamAsyncClient.java","src/main/java/azure/clientgenerator/core/clientinitialization/PathParamClient.java","src/main/java/azure/clientgenerator/core/clientinitialization/PathParamClientBuilder.java","src/main/java/azure/clientgenerator/core/clientinitialization/implementation/ChildClientImpl.java","src/main/java/azure/clientgenerator/core/clientinitialization/implementation/HeaderParamClientImpl.java","src/main/java/azure/clientgenerator/core/clientinitialization/implementation/MixedParamsClientImpl.java","src/main/java/azure/clientgenerator/core/clientinitialization/implementation/MultipleParamsClientImpl.java","src/main/java/azure/clientgenerator/core/clientinitialization/implementation/ParamAliasClientImpl.java","src/main/java/azure/clientgenerator/core/clientinitialization/implementation/ParentClientImpl.java","src/main/java/azure/clientgenerator/core/clientinitialization/implementation/PathParamClientImpl.java","src/main/java/azure/clientgenerator/core/clientinitialization/implementation/package-info.java","src/main/java/azure/clientgenerator/core/clientinitialization/models/BlobProperties.java","src/main/java/azure/clientgenerator/core/clientinitialization/models/Input.java","src/main/java/azure/clientgenerator/core/clientinitialization/models/WithBodyRequest.java","src/main/java/azure/clientgenerator/core/clientinitialization/models/package-info.java","src/main/java/azure/clientgenerator/core/clientinitialization/package-info.java","src/main/java/azure/clientgenerator/core/clientinitialization/parentclient/ChildAsyncClient.java","src/main/java/azure/clientgenerator/core/clientinitialization/parentclient/ChildClient.java","src/main/java/azure/clientgenerator/core/clientinitialization/parentclient/ChildClientBuilder.java","src/main/java/azure/clientgenerator/core/clientinitialization/parentclient/ParentAsyncClient.java","src/main/java/azure/clientgenerator/core/clientinitialization/parentclient/ParentClient.java","src/main/java/azure/clientgenerator/core/clientinitialization/parentclient/ParentClientBuilder.java","src/main/java/azure/clientgenerator/core/clientinitialization/parentclient/package-info.java","src/main/java/module-info.java"]} \ No newline at end of file +{"flavor":"Azure","crossLanguageDefinitions":{"azure.clientgenerator.core.clientinitialization.HeaderParamAsyncClient":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.HeaderParam","azure.clientgenerator.core.clientinitialization.HeaderParamAsyncClient.withBody":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.HeaderParam.withBody","azure.clientgenerator.core.clientinitialization.HeaderParamAsyncClient.withBodyWithResponse":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.HeaderParam.withBody","azure.clientgenerator.core.clientinitialization.HeaderParamAsyncClient.withQuery":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.HeaderParam.withQuery","azure.clientgenerator.core.clientinitialization.HeaderParamAsyncClient.withQueryWithResponse":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.HeaderParam.withQuery","azure.clientgenerator.core.clientinitialization.HeaderParamClient":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.HeaderParam","azure.clientgenerator.core.clientinitialization.HeaderParamClient.withBody":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.HeaderParam.withBody","azure.clientgenerator.core.clientinitialization.HeaderParamClient.withBodyWithResponse":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.HeaderParam.withBody","azure.clientgenerator.core.clientinitialization.HeaderParamClient.withQuery":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.HeaderParam.withQuery","azure.clientgenerator.core.clientinitialization.HeaderParamClient.withQueryWithResponse":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.HeaderParam.withQuery","azure.clientgenerator.core.clientinitialization.HeaderParamClientBuilder":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.HeaderParam","azure.clientgenerator.core.clientinitialization.MixedParamsAsyncClient":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MixedParams","azure.clientgenerator.core.clientinitialization.MixedParamsAsyncClient.withBody":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MixedParams.withBody","azure.clientgenerator.core.clientinitialization.MixedParamsAsyncClient.withBodyWithResponse":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MixedParams.withBody","azure.clientgenerator.core.clientinitialization.MixedParamsAsyncClient.withQuery":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MixedParams.withQuery","azure.clientgenerator.core.clientinitialization.MixedParamsAsyncClient.withQueryWithResponse":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MixedParams.withQuery","azure.clientgenerator.core.clientinitialization.MixedParamsClient":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MixedParams","azure.clientgenerator.core.clientinitialization.MixedParamsClient.withBody":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MixedParams.withBody","azure.clientgenerator.core.clientinitialization.MixedParamsClient.withBodyWithResponse":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MixedParams.withBody","azure.clientgenerator.core.clientinitialization.MixedParamsClient.withQuery":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MixedParams.withQuery","azure.clientgenerator.core.clientinitialization.MixedParamsClient.withQueryWithResponse":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MixedParams.withQuery","azure.clientgenerator.core.clientinitialization.MixedParamsClientBuilder":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MixedParams","azure.clientgenerator.core.clientinitialization.MultipleParamsAsyncClient":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MultipleParams","azure.clientgenerator.core.clientinitialization.MultipleParamsAsyncClient.withBody":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MultipleParams.withBody","azure.clientgenerator.core.clientinitialization.MultipleParamsAsyncClient.withBodyWithResponse":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MultipleParams.withBody","azure.clientgenerator.core.clientinitialization.MultipleParamsAsyncClient.withQuery":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MultipleParams.withQuery","azure.clientgenerator.core.clientinitialization.MultipleParamsAsyncClient.withQueryWithResponse":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MultipleParams.withQuery","azure.clientgenerator.core.clientinitialization.MultipleParamsClient":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MultipleParams","azure.clientgenerator.core.clientinitialization.MultipleParamsClient.withBody":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MultipleParams.withBody","azure.clientgenerator.core.clientinitialization.MultipleParamsClient.withBodyWithResponse":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MultipleParams.withBody","azure.clientgenerator.core.clientinitialization.MultipleParamsClient.withQuery":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MultipleParams.withQuery","azure.clientgenerator.core.clientinitialization.MultipleParamsClient.withQueryWithResponse":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MultipleParams.withQuery","azure.clientgenerator.core.clientinitialization.MultipleParamsClientBuilder":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.MultipleParams","azure.clientgenerator.core.clientinitialization.ParamAliasAsyncClient":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParamAlias","azure.clientgenerator.core.clientinitialization.ParamAliasAsyncClient.withAliasedName":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParamAlias.withAliasedName","azure.clientgenerator.core.clientinitialization.ParamAliasAsyncClient.withAliasedNameWithResponse":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParamAlias.withAliasedName","azure.clientgenerator.core.clientinitialization.ParamAliasAsyncClient.withOriginalName":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParamAlias.withOriginalName","azure.clientgenerator.core.clientinitialization.ParamAliasAsyncClient.withOriginalNameWithResponse":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParamAlias.withOriginalName","azure.clientgenerator.core.clientinitialization.ParamAliasClient":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParamAlias","azure.clientgenerator.core.clientinitialization.ParamAliasClient.withAliasedName":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParamAlias.withAliasedName","azure.clientgenerator.core.clientinitialization.ParamAliasClient.withAliasedNameWithResponse":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParamAlias.withAliasedName","azure.clientgenerator.core.clientinitialization.ParamAliasClient.withOriginalName":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParamAlias.withOriginalName","azure.clientgenerator.core.clientinitialization.ParamAliasClient.withOriginalNameWithResponse":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParamAlias.withOriginalName","azure.clientgenerator.core.clientinitialization.ParamAliasClientBuilder":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParamAlias","azure.clientgenerator.core.clientinitialization.PathParamAsyncClient":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.PathParam","azure.clientgenerator.core.clientinitialization.PathParamAsyncClient.deleteStandalone":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.PathParam.deleteStandalone","azure.clientgenerator.core.clientinitialization.PathParamAsyncClient.deleteStandaloneWithResponse":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.PathParam.deleteStandalone","azure.clientgenerator.core.clientinitialization.PathParamAsyncClient.getStandalone":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.PathParam.getStandalone","azure.clientgenerator.core.clientinitialization.PathParamAsyncClient.getStandaloneWithResponse":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.PathParam.getStandalone","azure.clientgenerator.core.clientinitialization.PathParamAsyncClient.withQuery":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.PathParam.withQuery","azure.clientgenerator.core.clientinitialization.PathParamAsyncClient.withQueryWithResponse":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.PathParam.withQuery","azure.clientgenerator.core.clientinitialization.PathParamClient":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.PathParam","azure.clientgenerator.core.clientinitialization.PathParamClient.deleteStandalone":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.PathParam.deleteStandalone","azure.clientgenerator.core.clientinitialization.PathParamClient.deleteStandaloneWithResponse":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.PathParam.deleteStandalone","azure.clientgenerator.core.clientinitialization.PathParamClient.getStandalone":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.PathParam.getStandalone","azure.clientgenerator.core.clientinitialization.PathParamClient.getStandaloneWithResponse":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.PathParam.getStandalone","azure.clientgenerator.core.clientinitialization.PathParamClient.withQuery":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.PathParam.withQuery","azure.clientgenerator.core.clientinitialization.PathParamClient.withQueryWithResponse":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.PathParam.withQuery","azure.clientgenerator.core.clientinitialization.PathParamClientBuilder":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.PathParam","azure.clientgenerator.core.clientinitialization.models.BlobProperties":"Service.BlobProperties","azure.clientgenerator.core.clientinitialization.models.Input":"Service.Input","azure.clientgenerator.core.clientinitialization.models.WithBodyRequest":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.withBody.Request.anonymous","azure.clientgenerator.core.clientinitialization.parentclient.ChildAsyncClient":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParentClient.ChildClient","azure.clientgenerator.core.clientinitialization.parentclient.ChildAsyncClient.deleteStandalone":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParentClient.ChildClient.deleteStandalone","azure.clientgenerator.core.clientinitialization.parentclient.ChildAsyncClient.deleteStandaloneWithResponse":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParentClient.ChildClient.deleteStandalone","azure.clientgenerator.core.clientinitialization.parentclient.ChildAsyncClient.getStandalone":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParentClient.ChildClient.getStandalone","azure.clientgenerator.core.clientinitialization.parentclient.ChildAsyncClient.getStandaloneWithResponse":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParentClient.ChildClient.getStandalone","azure.clientgenerator.core.clientinitialization.parentclient.ChildAsyncClient.withQuery":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParentClient.ChildClient.withQuery","azure.clientgenerator.core.clientinitialization.parentclient.ChildAsyncClient.withQueryWithResponse":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParentClient.ChildClient.withQuery","azure.clientgenerator.core.clientinitialization.parentclient.ChildClient":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParentClient.ChildClient","azure.clientgenerator.core.clientinitialization.parentclient.ChildClient.deleteStandalone":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParentClient.ChildClient.deleteStandalone","azure.clientgenerator.core.clientinitialization.parentclient.ChildClient.deleteStandaloneWithResponse":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParentClient.ChildClient.deleteStandalone","azure.clientgenerator.core.clientinitialization.parentclient.ChildClient.getStandalone":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParentClient.ChildClient.getStandalone","azure.clientgenerator.core.clientinitialization.parentclient.ChildClient.getStandaloneWithResponse":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParentClient.ChildClient.getStandalone","azure.clientgenerator.core.clientinitialization.parentclient.ChildClient.withQuery":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParentClient.ChildClient.withQuery","azure.clientgenerator.core.clientinitialization.parentclient.ChildClient.withQueryWithResponse":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParentClient.ChildClient.withQuery","azure.clientgenerator.core.clientinitialization.parentclient.ChildClientBuilder":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParentClient.ChildClient","azure.clientgenerator.core.clientinitialization.parentclient.ParentAsyncClient":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParentClient","azure.clientgenerator.core.clientinitialization.parentclient.ParentClient":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParentClient","azure.clientgenerator.core.clientinitialization.parentclient.ParentClientBuilder":"_Specs_.Azure.ClientGenerator.Core.ClientInitialization.ParentClient"},"generatedFiles":["src/main/java/azure/clientgenerator/core/clientinitialization/HeaderParamAsyncClient.java","src/main/java/azure/clientgenerator/core/clientinitialization/HeaderParamClient.java","src/main/java/azure/clientgenerator/core/clientinitialization/HeaderParamClientBuilder.java","src/main/java/azure/clientgenerator/core/clientinitialization/MixedParamsAsyncClient.java","src/main/java/azure/clientgenerator/core/clientinitialization/MixedParamsClient.java","src/main/java/azure/clientgenerator/core/clientinitialization/MixedParamsClientBuilder.java","src/main/java/azure/clientgenerator/core/clientinitialization/MultipleParamsAsyncClient.java","src/main/java/azure/clientgenerator/core/clientinitialization/MultipleParamsClient.java","src/main/java/azure/clientgenerator/core/clientinitialization/MultipleParamsClientBuilder.java","src/main/java/azure/clientgenerator/core/clientinitialization/ParamAliasAsyncClient.java","src/main/java/azure/clientgenerator/core/clientinitialization/ParamAliasClient.java","src/main/java/azure/clientgenerator/core/clientinitialization/ParamAliasClientBuilder.java","src/main/java/azure/clientgenerator/core/clientinitialization/PathParamAsyncClient.java","src/main/java/azure/clientgenerator/core/clientinitialization/PathParamClient.java","src/main/java/azure/clientgenerator/core/clientinitialization/PathParamClientBuilder.java","src/main/java/azure/clientgenerator/core/clientinitialization/implementation/ChildClientImpl.java","src/main/java/azure/clientgenerator/core/clientinitialization/implementation/HeaderParamClientImpl.java","src/main/java/azure/clientgenerator/core/clientinitialization/implementation/MixedParamsClientImpl.java","src/main/java/azure/clientgenerator/core/clientinitialization/implementation/MultipleParamsClientImpl.java","src/main/java/azure/clientgenerator/core/clientinitialization/implementation/ParamAliasClientImpl.java","src/main/java/azure/clientgenerator/core/clientinitialization/implementation/ParentClientImpl.java","src/main/java/azure/clientgenerator/core/clientinitialization/implementation/PathParamClientImpl.java","src/main/java/azure/clientgenerator/core/clientinitialization/implementation/package-info.java","src/main/java/azure/clientgenerator/core/clientinitialization/models/BlobProperties.java","src/main/java/azure/clientgenerator/core/clientinitialization/models/Input.java","src/main/java/azure/clientgenerator/core/clientinitialization/models/WithBodyRequest.java","src/main/java/azure/clientgenerator/core/clientinitialization/models/package-info.java","src/main/java/azure/clientgenerator/core/clientinitialization/package-info.java","src/main/java/azure/clientgenerator/core/clientinitialization/parentclient/ChildAsyncClient.java","src/main/java/azure/clientgenerator/core/clientinitialization/parentclient/ChildClient.java","src/main/java/azure/clientgenerator/core/clientinitialization/parentclient/ChildClientBuilder.java","src/main/java/azure/clientgenerator/core/clientinitialization/parentclient/ParentAsyncClient.java","src/main/java/azure/clientgenerator/core/clientinitialization/parentclient/ParentClient.java","src/main/java/azure/clientgenerator/core/clientinitialization/parentclient/ParentClientBuilder.java","src/main/java/azure/clientgenerator/core/clientinitialization/parentclient/package-info.java","src/main/java/module-info.java"]} \ No newline at end of file diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/documentation_apiview_properties.json b/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/documentation_apiview_properties.json new file mode 100644 index 00000000000..d2aa92134d7 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/documentation_apiview_properties.json @@ -0,0 +1,37 @@ +{ + "flavor": "Azure", + "CrossLanguageDefinitionId": { + "documentation.DocumentationClientBuilder": "Documentation", + "documentation.ListsAsyncClient": "Documentation.Lists", + "documentation.ListsAsyncClient.bulletPointsModel": "Documentation.Lists.bulletPointsModel", + "documentation.ListsAsyncClient.bulletPointsModelWithResponse": "Documentation.Lists.bulletPointsModel", + "documentation.ListsAsyncClient.bulletPointsOp": "Documentation.Lists.bulletPointsOp", + "documentation.ListsAsyncClient.bulletPointsOpWithResponse": "Documentation.Lists.bulletPointsOp", + "documentation.ListsAsyncClient.numbered": "Documentation.Lists.numbered", + "documentation.ListsAsyncClient.numberedWithResponse": "Documentation.Lists.numbered", + "documentation.ListsClient": "Documentation.Lists", + "documentation.ListsClient.bulletPointsModel": "Documentation.Lists.bulletPointsModel", + "documentation.ListsClient.bulletPointsModelWithResponse": "Documentation.Lists.bulletPointsModel", + "documentation.ListsClient.bulletPointsOp": "Documentation.Lists.bulletPointsOp", + "documentation.ListsClient.bulletPointsOpWithResponse": "Documentation.Lists.bulletPointsOp", + "documentation.ListsClient.numbered": "Documentation.Lists.numbered", + "documentation.ListsClient.numberedWithResponse": "Documentation.Lists.numbered", + "documentation.TextFormattingAsyncClient": "Documentation.TextFormatting", + "documentation.TextFormattingAsyncClient.boldText": "Documentation.TextFormatting.boldText", + "documentation.TextFormattingAsyncClient.boldTextWithResponse": "Documentation.TextFormatting.boldText", + "documentation.TextFormattingAsyncClient.combinedFormatting": "Documentation.TextFormatting.combinedFormatting", + "documentation.TextFormattingAsyncClient.combinedFormattingWithResponse": "Documentation.TextFormatting.combinedFormatting", + "documentation.TextFormattingAsyncClient.italicText": "Documentation.TextFormatting.italicText", + "documentation.TextFormattingAsyncClient.italicTextWithResponse": "Documentation.TextFormatting.italicText", + "documentation.TextFormattingClient": "Documentation.TextFormatting", + "documentation.TextFormattingClient.boldText": "Documentation.TextFormatting.boldText", + "documentation.TextFormattingClient.boldTextWithResponse": "Documentation.TextFormatting.boldText", + "documentation.TextFormattingClient.combinedFormatting": "Documentation.TextFormatting.combinedFormatting", + "documentation.TextFormattingClient.combinedFormattingWithResponse": "Documentation.TextFormatting.combinedFormatting", + "documentation.TextFormattingClient.italicText": "Documentation.TextFormatting.italicText", + "documentation.TextFormattingClient.italicTextWithResponse": "Documentation.TextFormatting.italicText", + "documentation.lists.implementation.models.BulletPointsModelRequest": "Documentation.Lists.bulletPointsModel.Request.anonymous", + "documentation.lists.models.BulletPointsEnum": "Documentation.Lists.BulletPointsEnum", + "documentation.lists.models.BulletPointsModel": "Documentation.Lists.BulletPointsModel" + } +} diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/documentation_metadata.json b/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/documentation_metadata.json new file mode 100644 index 00000000000..8e1a954c7f1 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/documentation_metadata.json @@ -0,0 +1 @@ +{"flavor":"Azure","crossLanguageDefinitions":{"documentation.DocumentationClientBuilder":"Documentation","documentation.ListsAsyncClient":"Documentation.Lists","documentation.ListsAsyncClient.bulletPointsModel":"Documentation.Lists.bulletPointsModel","documentation.ListsAsyncClient.bulletPointsModelWithResponse":"Documentation.Lists.bulletPointsModel","documentation.ListsAsyncClient.bulletPointsOp":"Documentation.Lists.bulletPointsOp","documentation.ListsAsyncClient.bulletPointsOpWithResponse":"Documentation.Lists.bulletPointsOp","documentation.ListsAsyncClient.numbered":"Documentation.Lists.numbered","documentation.ListsAsyncClient.numberedWithResponse":"Documentation.Lists.numbered","documentation.ListsClient":"Documentation.Lists","documentation.ListsClient.bulletPointsModel":"Documentation.Lists.bulletPointsModel","documentation.ListsClient.bulletPointsModelWithResponse":"Documentation.Lists.bulletPointsModel","documentation.ListsClient.bulletPointsOp":"Documentation.Lists.bulletPointsOp","documentation.ListsClient.bulletPointsOpWithResponse":"Documentation.Lists.bulletPointsOp","documentation.ListsClient.numbered":"Documentation.Lists.numbered","documentation.ListsClient.numberedWithResponse":"Documentation.Lists.numbered","documentation.TextFormattingAsyncClient":"Documentation.TextFormatting","documentation.TextFormattingAsyncClient.boldText":"Documentation.TextFormatting.boldText","documentation.TextFormattingAsyncClient.boldTextWithResponse":"Documentation.TextFormatting.boldText","documentation.TextFormattingAsyncClient.combinedFormatting":"Documentation.TextFormatting.combinedFormatting","documentation.TextFormattingAsyncClient.combinedFormattingWithResponse":"Documentation.TextFormatting.combinedFormatting","documentation.TextFormattingAsyncClient.italicText":"Documentation.TextFormatting.italicText","documentation.TextFormattingAsyncClient.italicTextWithResponse":"Documentation.TextFormatting.italicText","documentation.TextFormattingClient":"Documentation.TextFormatting","documentation.TextFormattingClient.boldText":"Documentation.TextFormatting.boldText","documentation.TextFormattingClient.boldTextWithResponse":"Documentation.TextFormatting.boldText","documentation.TextFormattingClient.combinedFormatting":"Documentation.TextFormatting.combinedFormatting","documentation.TextFormattingClient.combinedFormattingWithResponse":"Documentation.TextFormatting.combinedFormatting","documentation.TextFormattingClient.italicText":"Documentation.TextFormatting.italicText","documentation.TextFormattingClient.italicTextWithResponse":"Documentation.TextFormatting.italicText","documentation.lists.implementation.models.BulletPointsModelRequest":"Documentation.Lists.bulletPointsModel.Request.anonymous","documentation.lists.models.BulletPointsEnum":"Documentation.Lists.BulletPointsEnum","documentation.lists.models.BulletPointsModel":"Documentation.Lists.BulletPointsModel"},"generatedFiles":["src/main/java/documentation/DocumentationClientBuilder.java","src/main/java/documentation/ListsAsyncClient.java","src/main/java/documentation/ListsClient.java","src/main/java/documentation/TextFormattingAsyncClient.java","src/main/java/documentation/TextFormattingClient.java","src/main/java/documentation/implementation/DocumentationClientImpl.java","src/main/java/documentation/implementation/ListsImpl.java","src/main/java/documentation/implementation/TextFormattingsImpl.java","src/main/java/documentation/implementation/package-info.java","src/main/java/documentation/lists/implementation/models/BulletPointsModelRequest.java","src/main/java/documentation/lists/implementation/models/package-info.java","src/main/java/documentation/lists/models/BulletPointsEnum.java","src/main/java/documentation/lists/models/BulletPointsModel.java","src/main/java/documentation/lists/models/package-info.java","src/main/java/documentation/package-info.java","src/main/java/module-info.java"]} \ No newline at end of file diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/encode-array_apiview_properties.json b/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/encode-array_apiview_properties.json new file mode 100644 index 00000000000..47a20deb2f2 --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/encode-array_apiview_properties.json @@ -0,0 +1,28 @@ +{ + "flavor": "Azure", + "CrossLanguageDefinitionId": { + "encode.array.ArrayAsyncClient": "Encode.Array.Property", + "encode.array.ArrayAsyncClient.commaDelimited": "Encode.Array.Property.commaDelimited", + "encode.array.ArrayAsyncClient.commaDelimitedWithResponse": "Encode.Array.Property.commaDelimited", + "encode.array.ArrayAsyncClient.newlineDelimited": "Encode.Array.Property.newlineDelimited", + "encode.array.ArrayAsyncClient.newlineDelimitedWithResponse": "Encode.Array.Property.newlineDelimited", + "encode.array.ArrayAsyncClient.pipeDelimited": "Encode.Array.Property.pipeDelimited", + "encode.array.ArrayAsyncClient.pipeDelimitedWithResponse": "Encode.Array.Property.pipeDelimited", + "encode.array.ArrayAsyncClient.spaceDelimited": "Encode.Array.Property.spaceDelimited", + "encode.array.ArrayAsyncClient.spaceDelimitedWithResponse": "Encode.Array.Property.spaceDelimited", + "encode.array.ArrayClient": "Encode.Array.Property", + "encode.array.ArrayClient.commaDelimited": "Encode.Array.Property.commaDelimited", + "encode.array.ArrayClient.commaDelimitedWithResponse": "Encode.Array.Property.commaDelimited", + "encode.array.ArrayClient.newlineDelimited": "Encode.Array.Property.newlineDelimited", + "encode.array.ArrayClient.newlineDelimitedWithResponse": "Encode.Array.Property.newlineDelimited", + "encode.array.ArrayClient.pipeDelimited": "Encode.Array.Property.pipeDelimited", + "encode.array.ArrayClient.pipeDelimitedWithResponse": "Encode.Array.Property.pipeDelimited", + "encode.array.ArrayClient.spaceDelimited": "Encode.Array.Property.spaceDelimited", + "encode.array.ArrayClient.spaceDelimitedWithResponse": "Encode.Array.Property.spaceDelimited", + "encode.array.ArrayClientBuilder": "Encode.Array", + "encode.array.models.CommaDelimitedArrayProperty": "Encode.Array.CommaDelimitedArrayProperty", + "encode.array.models.NewlineDelimitedArrayProperty": "Encode.Array.NewlineDelimitedArrayProperty", + "encode.array.models.PipeDelimitedArrayProperty": "Encode.Array.PipeDelimitedArrayProperty", + "encode.array.models.SpaceDelimitedArrayProperty": "Encode.Array.SpaceDelimitedArrayProperty" + } +} diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/encode-array_metadata.json b/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/encode-array_metadata.json new file mode 100644 index 00000000000..a094a17ad8f --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/encode-array_metadata.json @@ -0,0 +1 @@ +{"flavor":"Azure","crossLanguageDefinitions":{"encode.array.ArrayAsyncClient":"Encode.Array.Property","encode.array.ArrayAsyncClient.commaDelimited":"Encode.Array.Property.commaDelimited","encode.array.ArrayAsyncClient.commaDelimitedWithResponse":"Encode.Array.Property.commaDelimited","encode.array.ArrayAsyncClient.newlineDelimited":"Encode.Array.Property.newlineDelimited","encode.array.ArrayAsyncClient.newlineDelimitedWithResponse":"Encode.Array.Property.newlineDelimited","encode.array.ArrayAsyncClient.pipeDelimited":"Encode.Array.Property.pipeDelimited","encode.array.ArrayAsyncClient.pipeDelimitedWithResponse":"Encode.Array.Property.pipeDelimited","encode.array.ArrayAsyncClient.spaceDelimited":"Encode.Array.Property.spaceDelimited","encode.array.ArrayAsyncClient.spaceDelimitedWithResponse":"Encode.Array.Property.spaceDelimited","encode.array.ArrayClient":"Encode.Array.Property","encode.array.ArrayClient.commaDelimited":"Encode.Array.Property.commaDelimited","encode.array.ArrayClient.commaDelimitedWithResponse":"Encode.Array.Property.commaDelimited","encode.array.ArrayClient.newlineDelimited":"Encode.Array.Property.newlineDelimited","encode.array.ArrayClient.newlineDelimitedWithResponse":"Encode.Array.Property.newlineDelimited","encode.array.ArrayClient.pipeDelimited":"Encode.Array.Property.pipeDelimited","encode.array.ArrayClient.pipeDelimitedWithResponse":"Encode.Array.Property.pipeDelimited","encode.array.ArrayClient.spaceDelimited":"Encode.Array.Property.spaceDelimited","encode.array.ArrayClient.spaceDelimitedWithResponse":"Encode.Array.Property.spaceDelimited","encode.array.ArrayClientBuilder":"Encode.Array","encode.array.models.CommaDelimitedArrayProperty":"Encode.Array.CommaDelimitedArrayProperty","encode.array.models.NewlineDelimitedArrayProperty":"Encode.Array.NewlineDelimitedArrayProperty","encode.array.models.PipeDelimitedArrayProperty":"Encode.Array.PipeDelimitedArrayProperty","encode.array.models.SpaceDelimitedArrayProperty":"Encode.Array.SpaceDelimitedArrayProperty"},"generatedFiles":["src/main/java/encode/array/ArrayAsyncClient.java","src/main/java/encode/array/ArrayClient.java","src/main/java/encode/array/ArrayClientBuilder.java","src/main/java/encode/array/implementation/ArrayClientImpl.java","src/main/java/encode/array/implementation/PropertiesImpl.java","src/main/java/encode/array/implementation/package-info.java","src/main/java/encode/array/models/CommaDelimitedArrayProperty.java","src/main/java/encode/array/models/NewlineDelimitedArrayProperty.java","src/main/java/encode/array/models/PipeDelimitedArrayProperty.java","src/main/java/encode/array/models/SpaceDelimitedArrayProperty.java","src/main/java/encode/array/models/package-info.java","src/main/java/encode/array/package-info.java","src/main/java/module-info.java"]} \ No newline at end of file diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/specialwords_apiview_properties.json b/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/specialwords_apiview_properties.json index b90bd80766c..8884bf558b4 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/specialwords_apiview_properties.json +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/specialwords_apiview_properties.json @@ -2,9 +2,13 @@ "flavor": "Azure", "CrossLanguageDefinitionId": { "specialwords.ModelPropertiesAsyncClient": "SpecialWords.ModelProperties", + "specialwords.ModelPropertiesAsyncClient.dictMethods": "SpecialWords.ModelProperties.dictMethods", + "specialwords.ModelPropertiesAsyncClient.dictMethodsWithResponse": "SpecialWords.ModelProperties.dictMethods", "specialwords.ModelPropertiesAsyncClient.sameAsModel": "SpecialWords.ModelProperties.sameAsModel", "specialwords.ModelPropertiesAsyncClient.sameAsModelWithResponse": "SpecialWords.ModelProperties.sameAsModel", "specialwords.ModelPropertiesClient": "SpecialWords.ModelProperties", + "specialwords.ModelPropertiesClient.dictMethods": "SpecialWords.ModelProperties.dictMethods", + "specialwords.ModelPropertiesClient.dictMethodsWithResponse": "SpecialWords.ModelProperties.dictMethods", "specialwords.ModelPropertiesClient.sameAsModel": "SpecialWords.ModelProperties.sameAsModel", "specialwords.ModelPropertiesClient.sameAsModelWithResponse": "SpecialWords.ModelProperties.sameAsModel", "specialwords.ModelsAsyncClient": "SpecialWords.Models", @@ -410,6 +414,7 @@ "specialwords.ParametersClient.withYield": "SpecialWords.Parameters.withYield", "specialwords.ParametersClient.withYieldWithResponse": "SpecialWords.Parameters.withYield", "specialwords.SpecialWordsClientBuilder": "SpecialWords", + "specialwords.modelproperties.models.DictMethods": "SpecialWords.ModelProperties.DictMethods", "specialwords.modelproperties.models.SameAsModel": "SpecialWords.ModelProperties.SameAsModel", "specialwords.models.models.And": "SpecialWords.Models.and", "specialwords.models.models.As": "SpecialWords.Models.as", diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/specialwords_metadata.json b/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/specialwords_metadata.json index b903c2970dd..b15d6bfff0e 100644 --- a/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/specialwords_metadata.json +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/resources/META-INF/specialwords_metadata.json @@ -1 +1 @@ -{"flavor":"Azure","crossLanguageDefinitions":{"specialwords.ModelPropertiesAsyncClient":"SpecialWords.ModelProperties","specialwords.ModelPropertiesAsyncClient.sameAsModel":"SpecialWords.ModelProperties.sameAsModel","specialwords.ModelPropertiesAsyncClient.sameAsModelWithResponse":"SpecialWords.ModelProperties.sameAsModel","specialwords.ModelPropertiesClient":"SpecialWords.ModelProperties","specialwords.ModelPropertiesClient.sameAsModel":"SpecialWords.ModelProperties.sameAsModel","specialwords.ModelPropertiesClient.sameAsModelWithResponse":"SpecialWords.ModelProperties.sameAsModel","specialwords.ModelsAsyncClient":"SpecialWords.Models","specialwords.ModelsAsyncClient.withAnd":"SpecialWords.Models.withAnd","specialwords.ModelsAsyncClient.withAndWithResponse":"SpecialWords.Models.withAnd","specialwords.ModelsAsyncClient.withAs":"SpecialWords.Models.withAs","specialwords.ModelsAsyncClient.withAsWithResponse":"SpecialWords.Models.withAs","specialwords.ModelsAsyncClient.withAssert":"SpecialWords.Models.withAssert","specialwords.ModelsAsyncClient.withAssertWithResponse":"SpecialWords.Models.withAssert","specialwords.ModelsAsyncClient.withAsyncWithResponse":"SpecialWords.Models.withAsync","specialwords.ModelsAsyncClient.withAwait":"SpecialWords.Models.withAwait","specialwords.ModelsAsyncClient.withAwaitWithResponse":"SpecialWords.Models.withAwait","specialwords.ModelsAsyncClient.withBreak":"SpecialWords.Models.withBreak","specialwords.ModelsAsyncClient.withBreakWithResponse":"SpecialWords.Models.withBreak","specialwords.ModelsAsyncClient.withClass":"SpecialWords.Models.withClass","specialwords.ModelsAsyncClient.withClassWithResponse":"SpecialWords.Models.withClass","specialwords.ModelsAsyncClient.withConstructor":"SpecialWords.Models.withConstructor","specialwords.ModelsAsyncClient.withConstructorWithResponse":"SpecialWords.Models.withConstructor","specialwords.ModelsAsyncClient.withContinue":"SpecialWords.Models.withContinue","specialwords.ModelsAsyncClient.withContinueWithResponse":"SpecialWords.Models.withContinue","specialwords.ModelsAsyncClient.withDef":"SpecialWords.Models.withDef","specialwords.ModelsAsyncClient.withDefWithResponse":"SpecialWords.Models.withDef","specialwords.ModelsAsyncClient.withDel":"SpecialWords.Models.withDel","specialwords.ModelsAsyncClient.withDelWithResponse":"SpecialWords.Models.withDel","specialwords.ModelsAsyncClient.withElif":"SpecialWords.Models.withElif","specialwords.ModelsAsyncClient.withElifWithResponse":"SpecialWords.Models.withElif","specialwords.ModelsAsyncClient.withElse":"SpecialWords.Models.withElse","specialwords.ModelsAsyncClient.withElseWithResponse":"SpecialWords.Models.withElse","specialwords.ModelsAsyncClient.withExcept":"SpecialWords.Models.withExcept","specialwords.ModelsAsyncClient.withExceptWithResponse":"SpecialWords.Models.withExcept","specialwords.ModelsAsyncClient.withExec":"SpecialWords.Models.withExec","specialwords.ModelsAsyncClient.withExecWithResponse":"SpecialWords.Models.withExec","specialwords.ModelsAsyncClient.withFinally":"SpecialWords.Models.withFinally","specialwords.ModelsAsyncClient.withFinallyWithResponse":"SpecialWords.Models.withFinally","specialwords.ModelsAsyncClient.withFor":"SpecialWords.Models.withFor","specialwords.ModelsAsyncClient.withForWithResponse":"SpecialWords.Models.withFor","specialwords.ModelsAsyncClient.withFrom":"SpecialWords.Models.withFrom","specialwords.ModelsAsyncClient.withFromWithResponse":"SpecialWords.Models.withFrom","specialwords.ModelsAsyncClient.withGlobal":"SpecialWords.Models.withGlobal","specialwords.ModelsAsyncClient.withGlobalWithResponse":"SpecialWords.Models.withGlobal","specialwords.ModelsAsyncClient.withIf":"SpecialWords.Models.withIf","specialwords.ModelsAsyncClient.withIfWithResponse":"SpecialWords.Models.withIf","specialwords.ModelsAsyncClient.withImport":"SpecialWords.Models.withImport","specialwords.ModelsAsyncClient.withImportWithResponse":"SpecialWords.Models.withImport","specialwords.ModelsAsyncClient.withIn":"SpecialWords.Models.withIn","specialwords.ModelsAsyncClient.withInWithResponse":"SpecialWords.Models.withIn","specialwords.ModelsAsyncClient.withIs":"SpecialWords.Models.withIs","specialwords.ModelsAsyncClient.withIsWithResponse":"SpecialWords.Models.withIs","specialwords.ModelsAsyncClient.withLambda":"SpecialWords.Models.withLambda","specialwords.ModelsAsyncClient.withLambdaWithResponse":"SpecialWords.Models.withLambda","specialwords.ModelsAsyncClient.withNot":"SpecialWords.Models.withNot","specialwords.ModelsAsyncClient.withNotWithResponse":"SpecialWords.Models.withNot","specialwords.ModelsAsyncClient.withOr":"SpecialWords.Models.withOr","specialwords.ModelsAsyncClient.withOrWithResponse":"SpecialWords.Models.withOr","specialwords.ModelsAsyncClient.withPass":"SpecialWords.Models.withPass","specialwords.ModelsAsyncClient.withPassWithResponse":"SpecialWords.Models.withPass","specialwords.ModelsAsyncClient.withRaise":"SpecialWords.Models.withRaise","specialwords.ModelsAsyncClient.withRaiseWithResponse":"SpecialWords.Models.withRaise","specialwords.ModelsAsyncClient.withReturn":"SpecialWords.Models.withReturn","specialwords.ModelsAsyncClient.withReturnWithResponse":"SpecialWords.Models.withReturn","specialwords.ModelsAsyncClient.withTry":"SpecialWords.Models.withTry","specialwords.ModelsAsyncClient.withTryWithResponse":"SpecialWords.Models.withTry","specialwords.ModelsAsyncClient.withWhile":"SpecialWords.Models.withWhile","specialwords.ModelsAsyncClient.withWhileWithResponse":"SpecialWords.Models.withWhile","specialwords.ModelsAsyncClient.withWith":"SpecialWords.Models.withWith","specialwords.ModelsAsyncClient.withWithWithResponse":"SpecialWords.Models.withWith","specialwords.ModelsAsyncClient.withYield":"SpecialWords.Models.withYield","specialwords.ModelsAsyncClient.withYieldWithResponse":"SpecialWords.Models.withYield","specialwords.ModelsClient":"SpecialWords.Models","specialwords.ModelsClient.withAnd":"SpecialWords.Models.withAnd","specialwords.ModelsClient.withAndWithResponse":"SpecialWords.Models.withAnd","specialwords.ModelsClient.withAs":"SpecialWords.Models.withAs","specialwords.ModelsClient.withAsWithResponse":"SpecialWords.Models.withAs","specialwords.ModelsClient.withAssert":"SpecialWords.Models.withAssert","specialwords.ModelsClient.withAssertWithResponse":"SpecialWords.Models.withAssert","specialwords.ModelsClient.withAsyncWithResponse":"SpecialWords.Models.withAsync","specialwords.ModelsClient.withAwait":"SpecialWords.Models.withAwait","specialwords.ModelsClient.withAwaitWithResponse":"SpecialWords.Models.withAwait","specialwords.ModelsClient.withBreak":"SpecialWords.Models.withBreak","specialwords.ModelsClient.withBreakWithResponse":"SpecialWords.Models.withBreak","specialwords.ModelsClient.withClass":"SpecialWords.Models.withClass","specialwords.ModelsClient.withClassWithResponse":"SpecialWords.Models.withClass","specialwords.ModelsClient.withConstructor":"SpecialWords.Models.withConstructor","specialwords.ModelsClient.withConstructorWithResponse":"SpecialWords.Models.withConstructor","specialwords.ModelsClient.withContinue":"SpecialWords.Models.withContinue","specialwords.ModelsClient.withContinueWithResponse":"SpecialWords.Models.withContinue","specialwords.ModelsClient.withDef":"SpecialWords.Models.withDef","specialwords.ModelsClient.withDefWithResponse":"SpecialWords.Models.withDef","specialwords.ModelsClient.withDel":"SpecialWords.Models.withDel","specialwords.ModelsClient.withDelWithResponse":"SpecialWords.Models.withDel","specialwords.ModelsClient.withElif":"SpecialWords.Models.withElif","specialwords.ModelsClient.withElifWithResponse":"SpecialWords.Models.withElif","specialwords.ModelsClient.withElse":"SpecialWords.Models.withElse","specialwords.ModelsClient.withElseWithResponse":"SpecialWords.Models.withElse","specialwords.ModelsClient.withExcept":"SpecialWords.Models.withExcept","specialwords.ModelsClient.withExceptWithResponse":"SpecialWords.Models.withExcept","specialwords.ModelsClient.withExec":"SpecialWords.Models.withExec","specialwords.ModelsClient.withExecWithResponse":"SpecialWords.Models.withExec","specialwords.ModelsClient.withFinally":"SpecialWords.Models.withFinally","specialwords.ModelsClient.withFinallyWithResponse":"SpecialWords.Models.withFinally","specialwords.ModelsClient.withFor":"SpecialWords.Models.withFor","specialwords.ModelsClient.withForWithResponse":"SpecialWords.Models.withFor","specialwords.ModelsClient.withFrom":"SpecialWords.Models.withFrom","specialwords.ModelsClient.withFromWithResponse":"SpecialWords.Models.withFrom","specialwords.ModelsClient.withGlobal":"SpecialWords.Models.withGlobal","specialwords.ModelsClient.withGlobalWithResponse":"SpecialWords.Models.withGlobal","specialwords.ModelsClient.withIf":"SpecialWords.Models.withIf","specialwords.ModelsClient.withIfWithResponse":"SpecialWords.Models.withIf","specialwords.ModelsClient.withImport":"SpecialWords.Models.withImport","specialwords.ModelsClient.withImportWithResponse":"SpecialWords.Models.withImport","specialwords.ModelsClient.withIn":"SpecialWords.Models.withIn","specialwords.ModelsClient.withInWithResponse":"SpecialWords.Models.withIn","specialwords.ModelsClient.withIs":"SpecialWords.Models.withIs","specialwords.ModelsClient.withIsWithResponse":"SpecialWords.Models.withIs","specialwords.ModelsClient.withLambda":"SpecialWords.Models.withLambda","specialwords.ModelsClient.withLambdaWithResponse":"SpecialWords.Models.withLambda","specialwords.ModelsClient.withNot":"SpecialWords.Models.withNot","specialwords.ModelsClient.withNotWithResponse":"SpecialWords.Models.withNot","specialwords.ModelsClient.withOr":"SpecialWords.Models.withOr","specialwords.ModelsClient.withOrWithResponse":"SpecialWords.Models.withOr","specialwords.ModelsClient.withPass":"SpecialWords.Models.withPass","specialwords.ModelsClient.withPassWithResponse":"SpecialWords.Models.withPass","specialwords.ModelsClient.withRaise":"SpecialWords.Models.withRaise","specialwords.ModelsClient.withRaiseWithResponse":"SpecialWords.Models.withRaise","specialwords.ModelsClient.withReturn":"SpecialWords.Models.withReturn","specialwords.ModelsClient.withReturnWithResponse":"SpecialWords.Models.withReturn","specialwords.ModelsClient.withTry":"SpecialWords.Models.withTry","specialwords.ModelsClient.withTryWithResponse":"SpecialWords.Models.withTry","specialwords.ModelsClient.withWhile":"SpecialWords.Models.withWhile","specialwords.ModelsClient.withWhileWithResponse":"SpecialWords.Models.withWhile","specialwords.ModelsClient.withWith":"SpecialWords.Models.withWith","specialwords.ModelsClient.withWithWithResponse":"SpecialWords.Models.withWith","specialwords.ModelsClient.withYield":"SpecialWords.Models.withYield","specialwords.ModelsClient.withYieldWithResponse":"SpecialWords.Models.withYield","specialwords.OperationsAsyncClient":"SpecialWords.Operations","specialwords.OperationsAsyncClient.and":"SpecialWords.Operations.and","specialwords.OperationsAsyncClient.andWithResponse":"SpecialWords.Operations.and","specialwords.OperationsAsyncClient.as":"SpecialWords.Operations.as","specialwords.OperationsAsyncClient.asWithResponse":"SpecialWords.Operations.as","specialwords.OperationsAsyncClient.assertMethod":"SpecialWords.Operations.assert","specialwords.OperationsAsyncClient.assertMethodWithResponse":"SpecialWords.Operations.assert","specialwords.OperationsAsyncClient.async":"SpecialWords.Operations.async","specialwords.OperationsAsyncClient.asyncWithResponse":"SpecialWords.Operations.async","specialwords.OperationsAsyncClient.await":"SpecialWords.Operations.await","specialwords.OperationsAsyncClient.awaitWithResponse":"SpecialWords.Operations.await","specialwords.OperationsAsyncClient.breakMethod":"SpecialWords.Operations.break","specialwords.OperationsAsyncClient.breakMethodWithResponse":"SpecialWords.Operations.break","specialwords.OperationsAsyncClient.classMethod":"SpecialWords.Operations.class","specialwords.OperationsAsyncClient.classMethodWithResponse":"SpecialWords.Operations.class","specialwords.OperationsAsyncClient.constructor":"SpecialWords.Operations.constructor","specialwords.OperationsAsyncClient.constructorWithResponse":"SpecialWords.Operations.constructor","specialwords.OperationsAsyncClient.continueMethod":"SpecialWords.Operations.continue","specialwords.OperationsAsyncClient.continueMethodWithResponse":"SpecialWords.Operations.continue","specialwords.OperationsAsyncClient.def":"SpecialWords.Operations.def","specialwords.OperationsAsyncClient.defWithResponse":"SpecialWords.Operations.def","specialwords.OperationsAsyncClient.del":"SpecialWords.Operations.del","specialwords.OperationsAsyncClient.delWithResponse":"SpecialWords.Operations.del","specialwords.OperationsAsyncClient.elif":"SpecialWords.Operations.elif","specialwords.OperationsAsyncClient.elifWithResponse":"SpecialWords.Operations.elif","specialwords.OperationsAsyncClient.elseMethod":"SpecialWords.Operations.else","specialwords.OperationsAsyncClient.elseMethodWithResponse":"SpecialWords.Operations.else","specialwords.OperationsAsyncClient.except":"SpecialWords.Operations.except","specialwords.OperationsAsyncClient.exceptWithResponse":"SpecialWords.Operations.except","specialwords.OperationsAsyncClient.exec":"SpecialWords.Operations.exec","specialwords.OperationsAsyncClient.execWithResponse":"SpecialWords.Operations.exec","specialwords.OperationsAsyncClient.finallyMethod":"SpecialWords.Operations.finally","specialwords.OperationsAsyncClient.finallyMethodWithResponse":"SpecialWords.Operations.finally","specialwords.OperationsAsyncClient.forMethod":"SpecialWords.Operations.for","specialwords.OperationsAsyncClient.forMethodWithResponse":"SpecialWords.Operations.for","specialwords.OperationsAsyncClient.from":"SpecialWords.Operations.from","specialwords.OperationsAsyncClient.fromWithResponse":"SpecialWords.Operations.from","specialwords.OperationsAsyncClient.global":"SpecialWords.Operations.global","specialwords.OperationsAsyncClient.globalWithResponse":"SpecialWords.Operations.global","specialwords.OperationsAsyncClient.ifMethod":"SpecialWords.Operations.if","specialwords.OperationsAsyncClient.ifMethodWithResponse":"SpecialWords.Operations.if","specialwords.OperationsAsyncClient.importMethod":"SpecialWords.Operations.import","specialwords.OperationsAsyncClient.importMethodWithResponse":"SpecialWords.Operations.import","specialwords.OperationsAsyncClient.in":"SpecialWords.Operations.in","specialwords.OperationsAsyncClient.inWithResponse":"SpecialWords.Operations.in","specialwords.OperationsAsyncClient.is":"SpecialWords.Operations.is","specialwords.OperationsAsyncClient.isWithResponse":"SpecialWords.Operations.is","specialwords.OperationsAsyncClient.lambda":"SpecialWords.Operations.lambda","specialwords.OperationsAsyncClient.lambdaWithResponse":"SpecialWords.Operations.lambda","specialwords.OperationsAsyncClient.not":"SpecialWords.Operations.not","specialwords.OperationsAsyncClient.notWithResponse":"SpecialWords.Operations.not","specialwords.OperationsAsyncClient.or":"SpecialWords.Operations.or","specialwords.OperationsAsyncClient.orWithResponse":"SpecialWords.Operations.or","specialwords.OperationsAsyncClient.pass":"SpecialWords.Operations.pass","specialwords.OperationsAsyncClient.passWithResponse":"SpecialWords.Operations.pass","specialwords.OperationsAsyncClient.raise":"SpecialWords.Operations.raise","specialwords.OperationsAsyncClient.raiseWithResponse":"SpecialWords.Operations.raise","specialwords.OperationsAsyncClient.returnMethod":"SpecialWords.Operations.return","specialwords.OperationsAsyncClient.returnMethodWithResponse":"SpecialWords.Operations.return","specialwords.OperationsAsyncClient.tryMethod":"SpecialWords.Operations.try","specialwords.OperationsAsyncClient.tryMethodWithResponse":"SpecialWords.Operations.try","specialwords.OperationsAsyncClient.whileMethod":"SpecialWords.Operations.while","specialwords.OperationsAsyncClient.whileMethodWithResponse":"SpecialWords.Operations.while","specialwords.OperationsAsyncClient.with":"SpecialWords.Operations.with","specialwords.OperationsAsyncClient.withWithResponse":"SpecialWords.Operations.with","specialwords.OperationsAsyncClient.yield":"SpecialWords.Operations.yield","specialwords.OperationsAsyncClient.yieldWithResponse":"SpecialWords.Operations.yield","specialwords.OperationsClient":"SpecialWords.Operations","specialwords.OperationsClient.and":"SpecialWords.Operations.and","specialwords.OperationsClient.andWithResponse":"SpecialWords.Operations.and","specialwords.OperationsClient.as":"SpecialWords.Operations.as","specialwords.OperationsClient.asWithResponse":"SpecialWords.Operations.as","specialwords.OperationsClient.assertMethod":"SpecialWords.Operations.assert","specialwords.OperationsClient.assertMethodWithResponse":"SpecialWords.Operations.assert","specialwords.OperationsClient.async":"SpecialWords.Operations.async","specialwords.OperationsClient.asyncWithResponse":"SpecialWords.Operations.async","specialwords.OperationsClient.await":"SpecialWords.Operations.await","specialwords.OperationsClient.awaitWithResponse":"SpecialWords.Operations.await","specialwords.OperationsClient.breakMethod":"SpecialWords.Operations.break","specialwords.OperationsClient.breakMethodWithResponse":"SpecialWords.Operations.break","specialwords.OperationsClient.classMethod":"SpecialWords.Operations.class","specialwords.OperationsClient.classMethodWithResponse":"SpecialWords.Operations.class","specialwords.OperationsClient.constructor":"SpecialWords.Operations.constructor","specialwords.OperationsClient.constructorWithResponse":"SpecialWords.Operations.constructor","specialwords.OperationsClient.continueMethod":"SpecialWords.Operations.continue","specialwords.OperationsClient.continueMethodWithResponse":"SpecialWords.Operations.continue","specialwords.OperationsClient.def":"SpecialWords.Operations.def","specialwords.OperationsClient.defWithResponse":"SpecialWords.Operations.def","specialwords.OperationsClient.del":"SpecialWords.Operations.del","specialwords.OperationsClient.delWithResponse":"SpecialWords.Operations.del","specialwords.OperationsClient.elif":"SpecialWords.Operations.elif","specialwords.OperationsClient.elifWithResponse":"SpecialWords.Operations.elif","specialwords.OperationsClient.elseMethod":"SpecialWords.Operations.else","specialwords.OperationsClient.elseMethodWithResponse":"SpecialWords.Operations.else","specialwords.OperationsClient.except":"SpecialWords.Operations.except","specialwords.OperationsClient.exceptWithResponse":"SpecialWords.Operations.except","specialwords.OperationsClient.exec":"SpecialWords.Operations.exec","specialwords.OperationsClient.execWithResponse":"SpecialWords.Operations.exec","specialwords.OperationsClient.finallyMethod":"SpecialWords.Operations.finally","specialwords.OperationsClient.finallyMethodWithResponse":"SpecialWords.Operations.finally","specialwords.OperationsClient.forMethod":"SpecialWords.Operations.for","specialwords.OperationsClient.forMethodWithResponse":"SpecialWords.Operations.for","specialwords.OperationsClient.from":"SpecialWords.Operations.from","specialwords.OperationsClient.fromWithResponse":"SpecialWords.Operations.from","specialwords.OperationsClient.global":"SpecialWords.Operations.global","specialwords.OperationsClient.globalWithResponse":"SpecialWords.Operations.global","specialwords.OperationsClient.ifMethod":"SpecialWords.Operations.if","specialwords.OperationsClient.ifMethodWithResponse":"SpecialWords.Operations.if","specialwords.OperationsClient.importMethod":"SpecialWords.Operations.import","specialwords.OperationsClient.importMethodWithResponse":"SpecialWords.Operations.import","specialwords.OperationsClient.in":"SpecialWords.Operations.in","specialwords.OperationsClient.inWithResponse":"SpecialWords.Operations.in","specialwords.OperationsClient.is":"SpecialWords.Operations.is","specialwords.OperationsClient.isWithResponse":"SpecialWords.Operations.is","specialwords.OperationsClient.lambda":"SpecialWords.Operations.lambda","specialwords.OperationsClient.lambdaWithResponse":"SpecialWords.Operations.lambda","specialwords.OperationsClient.not":"SpecialWords.Operations.not","specialwords.OperationsClient.notWithResponse":"SpecialWords.Operations.not","specialwords.OperationsClient.or":"SpecialWords.Operations.or","specialwords.OperationsClient.orWithResponse":"SpecialWords.Operations.or","specialwords.OperationsClient.pass":"SpecialWords.Operations.pass","specialwords.OperationsClient.passWithResponse":"SpecialWords.Operations.pass","specialwords.OperationsClient.raise":"SpecialWords.Operations.raise","specialwords.OperationsClient.raiseWithResponse":"SpecialWords.Operations.raise","specialwords.OperationsClient.returnMethod":"SpecialWords.Operations.return","specialwords.OperationsClient.returnMethodWithResponse":"SpecialWords.Operations.return","specialwords.OperationsClient.tryMethod":"SpecialWords.Operations.try","specialwords.OperationsClient.tryMethodWithResponse":"SpecialWords.Operations.try","specialwords.OperationsClient.whileMethod":"SpecialWords.Operations.while","specialwords.OperationsClient.whileMethodWithResponse":"SpecialWords.Operations.while","specialwords.OperationsClient.with":"SpecialWords.Operations.with","specialwords.OperationsClient.withWithResponse":"SpecialWords.Operations.with","specialwords.OperationsClient.yield":"SpecialWords.Operations.yield","specialwords.OperationsClient.yieldWithResponse":"SpecialWords.Operations.yield","specialwords.ParametersAsyncClient":"SpecialWords.Parameters","specialwords.ParametersAsyncClient.withAnd":"SpecialWords.Parameters.withAnd","specialwords.ParametersAsyncClient.withAndWithResponse":"SpecialWords.Parameters.withAnd","specialwords.ParametersAsyncClient.withAs":"SpecialWords.Parameters.withAs","specialwords.ParametersAsyncClient.withAsWithResponse":"SpecialWords.Parameters.withAs","specialwords.ParametersAsyncClient.withAssert":"SpecialWords.Parameters.withAssert","specialwords.ParametersAsyncClient.withAssertWithResponse":"SpecialWords.Parameters.withAssert","specialwords.ParametersAsyncClient.withAsyncWithResponse":"SpecialWords.Parameters.withAsync","specialwords.ParametersAsyncClient.withAwait":"SpecialWords.Parameters.withAwait","specialwords.ParametersAsyncClient.withAwaitWithResponse":"SpecialWords.Parameters.withAwait","specialwords.ParametersAsyncClient.withBreak":"SpecialWords.Parameters.withBreak","specialwords.ParametersAsyncClient.withBreakWithResponse":"SpecialWords.Parameters.withBreak","specialwords.ParametersAsyncClient.withCancellationToken":"SpecialWords.Parameters.withCancellationToken","specialwords.ParametersAsyncClient.withCancellationTokenWithResponse":"SpecialWords.Parameters.withCancellationToken","specialwords.ParametersAsyncClient.withClass":"SpecialWords.Parameters.withClass","specialwords.ParametersAsyncClient.withClassWithResponse":"SpecialWords.Parameters.withClass","specialwords.ParametersAsyncClient.withConstructor":"SpecialWords.Parameters.withConstructor","specialwords.ParametersAsyncClient.withConstructorWithResponse":"SpecialWords.Parameters.withConstructor","specialwords.ParametersAsyncClient.withContinue":"SpecialWords.Parameters.withContinue","specialwords.ParametersAsyncClient.withContinueWithResponse":"SpecialWords.Parameters.withContinue","specialwords.ParametersAsyncClient.withDef":"SpecialWords.Parameters.withDef","specialwords.ParametersAsyncClient.withDefWithResponse":"SpecialWords.Parameters.withDef","specialwords.ParametersAsyncClient.withDel":"SpecialWords.Parameters.withDel","specialwords.ParametersAsyncClient.withDelWithResponse":"SpecialWords.Parameters.withDel","specialwords.ParametersAsyncClient.withElif":"SpecialWords.Parameters.withElif","specialwords.ParametersAsyncClient.withElifWithResponse":"SpecialWords.Parameters.withElif","specialwords.ParametersAsyncClient.withElse":"SpecialWords.Parameters.withElse","specialwords.ParametersAsyncClient.withElseWithResponse":"SpecialWords.Parameters.withElse","specialwords.ParametersAsyncClient.withExcept":"SpecialWords.Parameters.withExcept","specialwords.ParametersAsyncClient.withExceptWithResponse":"SpecialWords.Parameters.withExcept","specialwords.ParametersAsyncClient.withExec":"SpecialWords.Parameters.withExec","specialwords.ParametersAsyncClient.withExecWithResponse":"SpecialWords.Parameters.withExec","specialwords.ParametersAsyncClient.withFinally":"SpecialWords.Parameters.withFinally","specialwords.ParametersAsyncClient.withFinallyWithResponse":"SpecialWords.Parameters.withFinally","specialwords.ParametersAsyncClient.withFor":"SpecialWords.Parameters.withFor","specialwords.ParametersAsyncClient.withForWithResponse":"SpecialWords.Parameters.withFor","specialwords.ParametersAsyncClient.withFrom":"SpecialWords.Parameters.withFrom","specialwords.ParametersAsyncClient.withFromWithResponse":"SpecialWords.Parameters.withFrom","specialwords.ParametersAsyncClient.withGlobal":"SpecialWords.Parameters.withGlobal","specialwords.ParametersAsyncClient.withGlobalWithResponse":"SpecialWords.Parameters.withGlobal","specialwords.ParametersAsyncClient.withIf":"SpecialWords.Parameters.withIf","specialwords.ParametersAsyncClient.withIfWithResponse":"SpecialWords.Parameters.withIf","specialwords.ParametersAsyncClient.withImport":"SpecialWords.Parameters.withImport","specialwords.ParametersAsyncClient.withImportWithResponse":"SpecialWords.Parameters.withImport","specialwords.ParametersAsyncClient.withIn":"SpecialWords.Parameters.withIn","specialwords.ParametersAsyncClient.withInWithResponse":"SpecialWords.Parameters.withIn","specialwords.ParametersAsyncClient.withIs":"SpecialWords.Parameters.withIs","specialwords.ParametersAsyncClient.withIsWithResponse":"SpecialWords.Parameters.withIs","specialwords.ParametersAsyncClient.withLambda":"SpecialWords.Parameters.withLambda","specialwords.ParametersAsyncClient.withLambdaWithResponse":"SpecialWords.Parameters.withLambda","specialwords.ParametersAsyncClient.withNot":"SpecialWords.Parameters.withNot","specialwords.ParametersAsyncClient.withNotWithResponse":"SpecialWords.Parameters.withNot","specialwords.ParametersAsyncClient.withOr":"SpecialWords.Parameters.withOr","specialwords.ParametersAsyncClient.withOrWithResponse":"SpecialWords.Parameters.withOr","specialwords.ParametersAsyncClient.withPass":"SpecialWords.Parameters.withPass","specialwords.ParametersAsyncClient.withPassWithResponse":"SpecialWords.Parameters.withPass","specialwords.ParametersAsyncClient.withRaise":"SpecialWords.Parameters.withRaise","specialwords.ParametersAsyncClient.withRaiseWithResponse":"SpecialWords.Parameters.withRaise","specialwords.ParametersAsyncClient.withReturn":"SpecialWords.Parameters.withReturn","specialwords.ParametersAsyncClient.withReturnWithResponse":"SpecialWords.Parameters.withReturn","specialwords.ParametersAsyncClient.withTry":"SpecialWords.Parameters.withTry","specialwords.ParametersAsyncClient.withTryWithResponse":"SpecialWords.Parameters.withTry","specialwords.ParametersAsyncClient.withWhile":"SpecialWords.Parameters.withWhile","specialwords.ParametersAsyncClient.withWhileWithResponse":"SpecialWords.Parameters.withWhile","specialwords.ParametersAsyncClient.withWith":"SpecialWords.Parameters.withWith","specialwords.ParametersAsyncClient.withWithWithResponse":"SpecialWords.Parameters.withWith","specialwords.ParametersAsyncClient.withYield":"SpecialWords.Parameters.withYield","specialwords.ParametersAsyncClient.withYieldWithResponse":"SpecialWords.Parameters.withYield","specialwords.ParametersClient":"SpecialWords.Parameters","specialwords.ParametersClient.withAnd":"SpecialWords.Parameters.withAnd","specialwords.ParametersClient.withAndWithResponse":"SpecialWords.Parameters.withAnd","specialwords.ParametersClient.withAs":"SpecialWords.Parameters.withAs","specialwords.ParametersClient.withAsWithResponse":"SpecialWords.Parameters.withAs","specialwords.ParametersClient.withAssert":"SpecialWords.Parameters.withAssert","specialwords.ParametersClient.withAssertWithResponse":"SpecialWords.Parameters.withAssert","specialwords.ParametersClient.withAsyncWithResponse":"SpecialWords.Parameters.withAsync","specialwords.ParametersClient.withAwait":"SpecialWords.Parameters.withAwait","specialwords.ParametersClient.withAwaitWithResponse":"SpecialWords.Parameters.withAwait","specialwords.ParametersClient.withBreak":"SpecialWords.Parameters.withBreak","specialwords.ParametersClient.withBreakWithResponse":"SpecialWords.Parameters.withBreak","specialwords.ParametersClient.withCancellationToken":"SpecialWords.Parameters.withCancellationToken","specialwords.ParametersClient.withCancellationTokenWithResponse":"SpecialWords.Parameters.withCancellationToken","specialwords.ParametersClient.withClass":"SpecialWords.Parameters.withClass","specialwords.ParametersClient.withClassWithResponse":"SpecialWords.Parameters.withClass","specialwords.ParametersClient.withConstructor":"SpecialWords.Parameters.withConstructor","specialwords.ParametersClient.withConstructorWithResponse":"SpecialWords.Parameters.withConstructor","specialwords.ParametersClient.withContinue":"SpecialWords.Parameters.withContinue","specialwords.ParametersClient.withContinueWithResponse":"SpecialWords.Parameters.withContinue","specialwords.ParametersClient.withDef":"SpecialWords.Parameters.withDef","specialwords.ParametersClient.withDefWithResponse":"SpecialWords.Parameters.withDef","specialwords.ParametersClient.withDel":"SpecialWords.Parameters.withDel","specialwords.ParametersClient.withDelWithResponse":"SpecialWords.Parameters.withDel","specialwords.ParametersClient.withElif":"SpecialWords.Parameters.withElif","specialwords.ParametersClient.withElifWithResponse":"SpecialWords.Parameters.withElif","specialwords.ParametersClient.withElse":"SpecialWords.Parameters.withElse","specialwords.ParametersClient.withElseWithResponse":"SpecialWords.Parameters.withElse","specialwords.ParametersClient.withExcept":"SpecialWords.Parameters.withExcept","specialwords.ParametersClient.withExceptWithResponse":"SpecialWords.Parameters.withExcept","specialwords.ParametersClient.withExec":"SpecialWords.Parameters.withExec","specialwords.ParametersClient.withExecWithResponse":"SpecialWords.Parameters.withExec","specialwords.ParametersClient.withFinally":"SpecialWords.Parameters.withFinally","specialwords.ParametersClient.withFinallyWithResponse":"SpecialWords.Parameters.withFinally","specialwords.ParametersClient.withFor":"SpecialWords.Parameters.withFor","specialwords.ParametersClient.withForWithResponse":"SpecialWords.Parameters.withFor","specialwords.ParametersClient.withFrom":"SpecialWords.Parameters.withFrom","specialwords.ParametersClient.withFromWithResponse":"SpecialWords.Parameters.withFrom","specialwords.ParametersClient.withGlobal":"SpecialWords.Parameters.withGlobal","specialwords.ParametersClient.withGlobalWithResponse":"SpecialWords.Parameters.withGlobal","specialwords.ParametersClient.withIf":"SpecialWords.Parameters.withIf","specialwords.ParametersClient.withIfWithResponse":"SpecialWords.Parameters.withIf","specialwords.ParametersClient.withImport":"SpecialWords.Parameters.withImport","specialwords.ParametersClient.withImportWithResponse":"SpecialWords.Parameters.withImport","specialwords.ParametersClient.withIn":"SpecialWords.Parameters.withIn","specialwords.ParametersClient.withInWithResponse":"SpecialWords.Parameters.withIn","specialwords.ParametersClient.withIs":"SpecialWords.Parameters.withIs","specialwords.ParametersClient.withIsWithResponse":"SpecialWords.Parameters.withIs","specialwords.ParametersClient.withLambda":"SpecialWords.Parameters.withLambda","specialwords.ParametersClient.withLambdaWithResponse":"SpecialWords.Parameters.withLambda","specialwords.ParametersClient.withNot":"SpecialWords.Parameters.withNot","specialwords.ParametersClient.withNotWithResponse":"SpecialWords.Parameters.withNot","specialwords.ParametersClient.withOr":"SpecialWords.Parameters.withOr","specialwords.ParametersClient.withOrWithResponse":"SpecialWords.Parameters.withOr","specialwords.ParametersClient.withPass":"SpecialWords.Parameters.withPass","specialwords.ParametersClient.withPassWithResponse":"SpecialWords.Parameters.withPass","specialwords.ParametersClient.withRaise":"SpecialWords.Parameters.withRaise","specialwords.ParametersClient.withRaiseWithResponse":"SpecialWords.Parameters.withRaise","specialwords.ParametersClient.withReturn":"SpecialWords.Parameters.withReturn","specialwords.ParametersClient.withReturnWithResponse":"SpecialWords.Parameters.withReturn","specialwords.ParametersClient.withTry":"SpecialWords.Parameters.withTry","specialwords.ParametersClient.withTryWithResponse":"SpecialWords.Parameters.withTry","specialwords.ParametersClient.withWhile":"SpecialWords.Parameters.withWhile","specialwords.ParametersClient.withWhileWithResponse":"SpecialWords.Parameters.withWhile","specialwords.ParametersClient.withWith":"SpecialWords.Parameters.withWith","specialwords.ParametersClient.withWithWithResponse":"SpecialWords.Parameters.withWith","specialwords.ParametersClient.withYield":"SpecialWords.Parameters.withYield","specialwords.ParametersClient.withYieldWithResponse":"SpecialWords.Parameters.withYield","specialwords.SpecialWordsClientBuilder":"SpecialWords","specialwords.modelproperties.models.SameAsModel":"SpecialWords.ModelProperties.SameAsModel","specialwords.models.models.And":"SpecialWords.Models.and","specialwords.models.models.As":"SpecialWords.Models.as","specialwords.models.models.Assert":"SpecialWords.Models.assert","specialwords.models.models.Async":"SpecialWords.Models.async","specialwords.models.models.Await":"SpecialWords.Models.await","specialwords.models.models.Break":"SpecialWords.Models.break","specialwords.models.models.ClassModel":"SpecialWords.Models.class","specialwords.models.models.Constructor":"SpecialWords.Models.constructor","specialwords.models.models.Continue":"SpecialWords.Models.continue","specialwords.models.models.Def":"SpecialWords.Models.def","specialwords.models.models.Del":"SpecialWords.Models.del","specialwords.models.models.Elif":"SpecialWords.Models.elif","specialwords.models.models.Else":"SpecialWords.Models.else","specialwords.models.models.Except":"SpecialWords.Models.except","specialwords.models.models.Exec":"SpecialWords.Models.exec","specialwords.models.models.Finally":"SpecialWords.Models.finally","specialwords.models.models.For":"SpecialWords.Models.for","specialwords.models.models.From":"SpecialWords.Models.from","specialwords.models.models.Global":"SpecialWords.Models.global","specialwords.models.models.If":"SpecialWords.Models.if","specialwords.models.models.Import":"SpecialWords.Models.import","specialwords.models.models.In":"SpecialWords.Models.in","specialwords.models.models.Is":"SpecialWords.Models.is","specialwords.models.models.Lambda":"SpecialWords.Models.lambda","specialwords.models.models.Not":"SpecialWords.Models.not","specialwords.models.models.Or":"SpecialWords.Models.or","specialwords.models.models.Pass":"SpecialWords.Models.pass","specialwords.models.models.Raise":"SpecialWords.Models.raise","specialwords.models.models.Return":"SpecialWords.Models.return","specialwords.models.models.Try":"SpecialWords.Models.try","specialwords.models.models.While":"SpecialWords.Models.while","specialwords.models.models.With":"SpecialWords.Models.with","specialwords.models.models.Yield":"SpecialWords.Models.yield"},"generatedFiles":["src/main/java/module-info.java","src/main/java/specialwords/ModelPropertiesAsyncClient.java","src/main/java/specialwords/ModelPropertiesClient.java","src/main/java/specialwords/ModelsAsyncClient.java","src/main/java/specialwords/ModelsClient.java","src/main/java/specialwords/OperationsAsyncClient.java","src/main/java/specialwords/OperationsClient.java","src/main/java/specialwords/ParametersAsyncClient.java","src/main/java/specialwords/ParametersClient.java","src/main/java/specialwords/SpecialWordsClientBuilder.java","src/main/java/specialwords/implementation/ModelPropertiesImpl.java","src/main/java/specialwords/implementation/ModelsImpl.java","src/main/java/specialwords/implementation/OperationsImpl.java","src/main/java/specialwords/implementation/ParametersImpl.java","src/main/java/specialwords/implementation/SpecialWordsClientImpl.java","src/main/java/specialwords/implementation/package-info.java","src/main/java/specialwords/modelproperties/models/SameAsModel.java","src/main/java/specialwords/modelproperties/models/package-info.java","src/main/java/specialwords/models/models/And.java","src/main/java/specialwords/models/models/As.java","src/main/java/specialwords/models/models/Assert.java","src/main/java/specialwords/models/models/Async.java","src/main/java/specialwords/models/models/Await.java","src/main/java/specialwords/models/models/Break.java","src/main/java/specialwords/models/models/ClassModel.java","src/main/java/specialwords/models/models/Constructor.java","src/main/java/specialwords/models/models/Continue.java","src/main/java/specialwords/models/models/Def.java","src/main/java/specialwords/models/models/Del.java","src/main/java/specialwords/models/models/Elif.java","src/main/java/specialwords/models/models/Else.java","src/main/java/specialwords/models/models/Except.java","src/main/java/specialwords/models/models/Exec.java","src/main/java/specialwords/models/models/Finally.java","src/main/java/specialwords/models/models/For.java","src/main/java/specialwords/models/models/From.java","src/main/java/specialwords/models/models/Global.java","src/main/java/specialwords/models/models/If.java","src/main/java/specialwords/models/models/Import.java","src/main/java/specialwords/models/models/In.java","src/main/java/specialwords/models/models/Is.java","src/main/java/specialwords/models/models/Lambda.java","src/main/java/specialwords/models/models/Not.java","src/main/java/specialwords/models/models/Or.java","src/main/java/specialwords/models/models/Pass.java","src/main/java/specialwords/models/models/Raise.java","src/main/java/specialwords/models/models/Return.java","src/main/java/specialwords/models/models/Try.java","src/main/java/specialwords/models/models/While.java","src/main/java/specialwords/models/models/With.java","src/main/java/specialwords/models/models/Yield.java","src/main/java/specialwords/models/models/package-info.java","src/main/java/specialwords/package-info.java"]} \ No newline at end of file +{"flavor":"Azure","crossLanguageDefinitions":{"specialwords.ModelPropertiesAsyncClient":"SpecialWords.ModelProperties","specialwords.ModelPropertiesAsyncClient.dictMethods":"SpecialWords.ModelProperties.dictMethods","specialwords.ModelPropertiesAsyncClient.dictMethodsWithResponse":"SpecialWords.ModelProperties.dictMethods","specialwords.ModelPropertiesAsyncClient.sameAsModel":"SpecialWords.ModelProperties.sameAsModel","specialwords.ModelPropertiesAsyncClient.sameAsModelWithResponse":"SpecialWords.ModelProperties.sameAsModel","specialwords.ModelPropertiesClient":"SpecialWords.ModelProperties","specialwords.ModelPropertiesClient.dictMethods":"SpecialWords.ModelProperties.dictMethods","specialwords.ModelPropertiesClient.dictMethodsWithResponse":"SpecialWords.ModelProperties.dictMethods","specialwords.ModelPropertiesClient.sameAsModel":"SpecialWords.ModelProperties.sameAsModel","specialwords.ModelPropertiesClient.sameAsModelWithResponse":"SpecialWords.ModelProperties.sameAsModel","specialwords.ModelsAsyncClient":"SpecialWords.Models","specialwords.ModelsAsyncClient.withAnd":"SpecialWords.Models.withAnd","specialwords.ModelsAsyncClient.withAndWithResponse":"SpecialWords.Models.withAnd","specialwords.ModelsAsyncClient.withAs":"SpecialWords.Models.withAs","specialwords.ModelsAsyncClient.withAsWithResponse":"SpecialWords.Models.withAs","specialwords.ModelsAsyncClient.withAssert":"SpecialWords.Models.withAssert","specialwords.ModelsAsyncClient.withAssertWithResponse":"SpecialWords.Models.withAssert","specialwords.ModelsAsyncClient.withAsyncWithResponse":"SpecialWords.Models.withAsync","specialwords.ModelsAsyncClient.withAwait":"SpecialWords.Models.withAwait","specialwords.ModelsAsyncClient.withAwaitWithResponse":"SpecialWords.Models.withAwait","specialwords.ModelsAsyncClient.withBreak":"SpecialWords.Models.withBreak","specialwords.ModelsAsyncClient.withBreakWithResponse":"SpecialWords.Models.withBreak","specialwords.ModelsAsyncClient.withClass":"SpecialWords.Models.withClass","specialwords.ModelsAsyncClient.withClassWithResponse":"SpecialWords.Models.withClass","specialwords.ModelsAsyncClient.withConstructor":"SpecialWords.Models.withConstructor","specialwords.ModelsAsyncClient.withConstructorWithResponse":"SpecialWords.Models.withConstructor","specialwords.ModelsAsyncClient.withContinue":"SpecialWords.Models.withContinue","specialwords.ModelsAsyncClient.withContinueWithResponse":"SpecialWords.Models.withContinue","specialwords.ModelsAsyncClient.withDef":"SpecialWords.Models.withDef","specialwords.ModelsAsyncClient.withDefWithResponse":"SpecialWords.Models.withDef","specialwords.ModelsAsyncClient.withDel":"SpecialWords.Models.withDel","specialwords.ModelsAsyncClient.withDelWithResponse":"SpecialWords.Models.withDel","specialwords.ModelsAsyncClient.withElif":"SpecialWords.Models.withElif","specialwords.ModelsAsyncClient.withElifWithResponse":"SpecialWords.Models.withElif","specialwords.ModelsAsyncClient.withElse":"SpecialWords.Models.withElse","specialwords.ModelsAsyncClient.withElseWithResponse":"SpecialWords.Models.withElse","specialwords.ModelsAsyncClient.withExcept":"SpecialWords.Models.withExcept","specialwords.ModelsAsyncClient.withExceptWithResponse":"SpecialWords.Models.withExcept","specialwords.ModelsAsyncClient.withExec":"SpecialWords.Models.withExec","specialwords.ModelsAsyncClient.withExecWithResponse":"SpecialWords.Models.withExec","specialwords.ModelsAsyncClient.withFinally":"SpecialWords.Models.withFinally","specialwords.ModelsAsyncClient.withFinallyWithResponse":"SpecialWords.Models.withFinally","specialwords.ModelsAsyncClient.withFor":"SpecialWords.Models.withFor","specialwords.ModelsAsyncClient.withForWithResponse":"SpecialWords.Models.withFor","specialwords.ModelsAsyncClient.withFrom":"SpecialWords.Models.withFrom","specialwords.ModelsAsyncClient.withFromWithResponse":"SpecialWords.Models.withFrom","specialwords.ModelsAsyncClient.withGlobal":"SpecialWords.Models.withGlobal","specialwords.ModelsAsyncClient.withGlobalWithResponse":"SpecialWords.Models.withGlobal","specialwords.ModelsAsyncClient.withIf":"SpecialWords.Models.withIf","specialwords.ModelsAsyncClient.withIfWithResponse":"SpecialWords.Models.withIf","specialwords.ModelsAsyncClient.withImport":"SpecialWords.Models.withImport","specialwords.ModelsAsyncClient.withImportWithResponse":"SpecialWords.Models.withImport","specialwords.ModelsAsyncClient.withIn":"SpecialWords.Models.withIn","specialwords.ModelsAsyncClient.withInWithResponse":"SpecialWords.Models.withIn","specialwords.ModelsAsyncClient.withIs":"SpecialWords.Models.withIs","specialwords.ModelsAsyncClient.withIsWithResponse":"SpecialWords.Models.withIs","specialwords.ModelsAsyncClient.withLambda":"SpecialWords.Models.withLambda","specialwords.ModelsAsyncClient.withLambdaWithResponse":"SpecialWords.Models.withLambda","specialwords.ModelsAsyncClient.withNot":"SpecialWords.Models.withNot","specialwords.ModelsAsyncClient.withNotWithResponse":"SpecialWords.Models.withNot","specialwords.ModelsAsyncClient.withOr":"SpecialWords.Models.withOr","specialwords.ModelsAsyncClient.withOrWithResponse":"SpecialWords.Models.withOr","specialwords.ModelsAsyncClient.withPass":"SpecialWords.Models.withPass","specialwords.ModelsAsyncClient.withPassWithResponse":"SpecialWords.Models.withPass","specialwords.ModelsAsyncClient.withRaise":"SpecialWords.Models.withRaise","specialwords.ModelsAsyncClient.withRaiseWithResponse":"SpecialWords.Models.withRaise","specialwords.ModelsAsyncClient.withReturn":"SpecialWords.Models.withReturn","specialwords.ModelsAsyncClient.withReturnWithResponse":"SpecialWords.Models.withReturn","specialwords.ModelsAsyncClient.withTry":"SpecialWords.Models.withTry","specialwords.ModelsAsyncClient.withTryWithResponse":"SpecialWords.Models.withTry","specialwords.ModelsAsyncClient.withWhile":"SpecialWords.Models.withWhile","specialwords.ModelsAsyncClient.withWhileWithResponse":"SpecialWords.Models.withWhile","specialwords.ModelsAsyncClient.withWith":"SpecialWords.Models.withWith","specialwords.ModelsAsyncClient.withWithWithResponse":"SpecialWords.Models.withWith","specialwords.ModelsAsyncClient.withYield":"SpecialWords.Models.withYield","specialwords.ModelsAsyncClient.withYieldWithResponse":"SpecialWords.Models.withYield","specialwords.ModelsClient":"SpecialWords.Models","specialwords.ModelsClient.withAnd":"SpecialWords.Models.withAnd","specialwords.ModelsClient.withAndWithResponse":"SpecialWords.Models.withAnd","specialwords.ModelsClient.withAs":"SpecialWords.Models.withAs","specialwords.ModelsClient.withAsWithResponse":"SpecialWords.Models.withAs","specialwords.ModelsClient.withAssert":"SpecialWords.Models.withAssert","specialwords.ModelsClient.withAssertWithResponse":"SpecialWords.Models.withAssert","specialwords.ModelsClient.withAsyncWithResponse":"SpecialWords.Models.withAsync","specialwords.ModelsClient.withAwait":"SpecialWords.Models.withAwait","specialwords.ModelsClient.withAwaitWithResponse":"SpecialWords.Models.withAwait","specialwords.ModelsClient.withBreak":"SpecialWords.Models.withBreak","specialwords.ModelsClient.withBreakWithResponse":"SpecialWords.Models.withBreak","specialwords.ModelsClient.withClass":"SpecialWords.Models.withClass","specialwords.ModelsClient.withClassWithResponse":"SpecialWords.Models.withClass","specialwords.ModelsClient.withConstructor":"SpecialWords.Models.withConstructor","specialwords.ModelsClient.withConstructorWithResponse":"SpecialWords.Models.withConstructor","specialwords.ModelsClient.withContinue":"SpecialWords.Models.withContinue","specialwords.ModelsClient.withContinueWithResponse":"SpecialWords.Models.withContinue","specialwords.ModelsClient.withDef":"SpecialWords.Models.withDef","specialwords.ModelsClient.withDefWithResponse":"SpecialWords.Models.withDef","specialwords.ModelsClient.withDel":"SpecialWords.Models.withDel","specialwords.ModelsClient.withDelWithResponse":"SpecialWords.Models.withDel","specialwords.ModelsClient.withElif":"SpecialWords.Models.withElif","specialwords.ModelsClient.withElifWithResponse":"SpecialWords.Models.withElif","specialwords.ModelsClient.withElse":"SpecialWords.Models.withElse","specialwords.ModelsClient.withElseWithResponse":"SpecialWords.Models.withElse","specialwords.ModelsClient.withExcept":"SpecialWords.Models.withExcept","specialwords.ModelsClient.withExceptWithResponse":"SpecialWords.Models.withExcept","specialwords.ModelsClient.withExec":"SpecialWords.Models.withExec","specialwords.ModelsClient.withExecWithResponse":"SpecialWords.Models.withExec","specialwords.ModelsClient.withFinally":"SpecialWords.Models.withFinally","specialwords.ModelsClient.withFinallyWithResponse":"SpecialWords.Models.withFinally","specialwords.ModelsClient.withFor":"SpecialWords.Models.withFor","specialwords.ModelsClient.withForWithResponse":"SpecialWords.Models.withFor","specialwords.ModelsClient.withFrom":"SpecialWords.Models.withFrom","specialwords.ModelsClient.withFromWithResponse":"SpecialWords.Models.withFrom","specialwords.ModelsClient.withGlobal":"SpecialWords.Models.withGlobal","specialwords.ModelsClient.withGlobalWithResponse":"SpecialWords.Models.withGlobal","specialwords.ModelsClient.withIf":"SpecialWords.Models.withIf","specialwords.ModelsClient.withIfWithResponse":"SpecialWords.Models.withIf","specialwords.ModelsClient.withImport":"SpecialWords.Models.withImport","specialwords.ModelsClient.withImportWithResponse":"SpecialWords.Models.withImport","specialwords.ModelsClient.withIn":"SpecialWords.Models.withIn","specialwords.ModelsClient.withInWithResponse":"SpecialWords.Models.withIn","specialwords.ModelsClient.withIs":"SpecialWords.Models.withIs","specialwords.ModelsClient.withIsWithResponse":"SpecialWords.Models.withIs","specialwords.ModelsClient.withLambda":"SpecialWords.Models.withLambda","specialwords.ModelsClient.withLambdaWithResponse":"SpecialWords.Models.withLambda","specialwords.ModelsClient.withNot":"SpecialWords.Models.withNot","specialwords.ModelsClient.withNotWithResponse":"SpecialWords.Models.withNot","specialwords.ModelsClient.withOr":"SpecialWords.Models.withOr","specialwords.ModelsClient.withOrWithResponse":"SpecialWords.Models.withOr","specialwords.ModelsClient.withPass":"SpecialWords.Models.withPass","specialwords.ModelsClient.withPassWithResponse":"SpecialWords.Models.withPass","specialwords.ModelsClient.withRaise":"SpecialWords.Models.withRaise","specialwords.ModelsClient.withRaiseWithResponse":"SpecialWords.Models.withRaise","specialwords.ModelsClient.withReturn":"SpecialWords.Models.withReturn","specialwords.ModelsClient.withReturnWithResponse":"SpecialWords.Models.withReturn","specialwords.ModelsClient.withTry":"SpecialWords.Models.withTry","specialwords.ModelsClient.withTryWithResponse":"SpecialWords.Models.withTry","specialwords.ModelsClient.withWhile":"SpecialWords.Models.withWhile","specialwords.ModelsClient.withWhileWithResponse":"SpecialWords.Models.withWhile","specialwords.ModelsClient.withWith":"SpecialWords.Models.withWith","specialwords.ModelsClient.withWithWithResponse":"SpecialWords.Models.withWith","specialwords.ModelsClient.withYield":"SpecialWords.Models.withYield","specialwords.ModelsClient.withYieldWithResponse":"SpecialWords.Models.withYield","specialwords.OperationsAsyncClient":"SpecialWords.Operations","specialwords.OperationsAsyncClient.and":"SpecialWords.Operations.and","specialwords.OperationsAsyncClient.andWithResponse":"SpecialWords.Operations.and","specialwords.OperationsAsyncClient.as":"SpecialWords.Operations.as","specialwords.OperationsAsyncClient.asWithResponse":"SpecialWords.Operations.as","specialwords.OperationsAsyncClient.assertMethod":"SpecialWords.Operations.assert","specialwords.OperationsAsyncClient.assertMethodWithResponse":"SpecialWords.Operations.assert","specialwords.OperationsAsyncClient.async":"SpecialWords.Operations.async","specialwords.OperationsAsyncClient.asyncWithResponse":"SpecialWords.Operations.async","specialwords.OperationsAsyncClient.await":"SpecialWords.Operations.await","specialwords.OperationsAsyncClient.awaitWithResponse":"SpecialWords.Operations.await","specialwords.OperationsAsyncClient.breakMethod":"SpecialWords.Operations.break","specialwords.OperationsAsyncClient.breakMethodWithResponse":"SpecialWords.Operations.break","specialwords.OperationsAsyncClient.classMethod":"SpecialWords.Operations.class","specialwords.OperationsAsyncClient.classMethodWithResponse":"SpecialWords.Operations.class","specialwords.OperationsAsyncClient.constructor":"SpecialWords.Operations.constructor","specialwords.OperationsAsyncClient.constructorWithResponse":"SpecialWords.Operations.constructor","specialwords.OperationsAsyncClient.continueMethod":"SpecialWords.Operations.continue","specialwords.OperationsAsyncClient.continueMethodWithResponse":"SpecialWords.Operations.continue","specialwords.OperationsAsyncClient.def":"SpecialWords.Operations.def","specialwords.OperationsAsyncClient.defWithResponse":"SpecialWords.Operations.def","specialwords.OperationsAsyncClient.del":"SpecialWords.Operations.del","specialwords.OperationsAsyncClient.delWithResponse":"SpecialWords.Operations.del","specialwords.OperationsAsyncClient.elif":"SpecialWords.Operations.elif","specialwords.OperationsAsyncClient.elifWithResponse":"SpecialWords.Operations.elif","specialwords.OperationsAsyncClient.elseMethod":"SpecialWords.Operations.else","specialwords.OperationsAsyncClient.elseMethodWithResponse":"SpecialWords.Operations.else","specialwords.OperationsAsyncClient.except":"SpecialWords.Operations.except","specialwords.OperationsAsyncClient.exceptWithResponse":"SpecialWords.Operations.except","specialwords.OperationsAsyncClient.exec":"SpecialWords.Operations.exec","specialwords.OperationsAsyncClient.execWithResponse":"SpecialWords.Operations.exec","specialwords.OperationsAsyncClient.finallyMethod":"SpecialWords.Operations.finally","specialwords.OperationsAsyncClient.finallyMethodWithResponse":"SpecialWords.Operations.finally","specialwords.OperationsAsyncClient.forMethod":"SpecialWords.Operations.for","specialwords.OperationsAsyncClient.forMethodWithResponse":"SpecialWords.Operations.for","specialwords.OperationsAsyncClient.from":"SpecialWords.Operations.from","specialwords.OperationsAsyncClient.fromWithResponse":"SpecialWords.Operations.from","specialwords.OperationsAsyncClient.global":"SpecialWords.Operations.global","specialwords.OperationsAsyncClient.globalWithResponse":"SpecialWords.Operations.global","specialwords.OperationsAsyncClient.ifMethod":"SpecialWords.Operations.if","specialwords.OperationsAsyncClient.ifMethodWithResponse":"SpecialWords.Operations.if","specialwords.OperationsAsyncClient.importMethod":"SpecialWords.Operations.import","specialwords.OperationsAsyncClient.importMethodWithResponse":"SpecialWords.Operations.import","specialwords.OperationsAsyncClient.in":"SpecialWords.Operations.in","specialwords.OperationsAsyncClient.inWithResponse":"SpecialWords.Operations.in","specialwords.OperationsAsyncClient.is":"SpecialWords.Operations.is","specialwords.OperationsAsyncClient.isWithResponse":"SpecialWords.Operations.is","specialwords.OperationsAsyncClient.lambda":"SpecialWords.Operations.lambda","specialwords.OperationsAsyncClient.lambdaWithResponse":"SpecialWords.Operations.lambda","specialwords.OperationsAsyncClient.not":"SpecialWords.Operations.not","specialwords.OperationsAsyncClient.notWithResponse":"SpecialWords.Operations.not","specialwords.OperationsAsyncClient.or":"SpecialWords.Operations.or","specialwords.OperationsAsyncClient.orWithResponse":"SpecialWords.Operations.or","specialwords.OperationsAsyncClient.pass":"SpecialWords.Operations.pass","specialwords.OperationsAsyncClient.passWithResponse":"SpecialWords.Operations.pass","specialwords.OperationsAsyncClient.raise":"SpecialWords.Operations.raise","specialwords.OperationsAsyncClient.raiseWithResponse":"SpecialWords.Operations.raise","specialwords.OperationsAsyncClient.returnMethod":"SpecialWords.Operations.return","specialwords.OperationsAsyncClient.returnMethodWithResponse":"SpecialWords.Operations.return","specialwords.OperationsAsyncClient.tryMethod":"SpecialWords.Operations.try","specialwords.OperationsAsyncClient.tryMethodWithResponse":"SpecialWords.Operations.try","specialwords.OperationsAsyncClient.whileMethod":"SpecialWords.Operations.while","specialwords.OperationsAsyncClient.whileMethodWithResponse":"SpecialWords.Operations.while","specialwords.OperationsAsyncClient.with":"SpecialWords.Operations.with","specialwords.OperationsAsyncClient.withWithResponse":"SpecialWords.Operations.with","specialwords.OperationsAsyncClient.yield":"SpecialWords.Operations.yield","specialwords.OperationsAsyncClient.yieldWithResponse":"SpecialWords.Operations.yield","specialwords.OperationsClient":"SpecialWords.Operations","specialwords.OperationsClient.and":"SpecialWords.Operations.and","specialwords.OperationsClient.andWithResponse":"SpecialWords.Operations.and","specialwords.OperationsClient.as":"SpecialWords.Operations.as","specialwords.OperationsClient.asWithResponse":"SpecialWords.Operations.as","specialwords.OperationsClient.assertMethod":"SpecialWords.Operations.assert","specialwords.OperationsClient.assertMethodWithResponse":"SpecialWords.Operations.assert","specialwords.OperationsClient.async":"SpecialWords.Operations.async","specialwords.OperationsClient.asyncWithResponse":"SpecialWords.Operations.async","specialwords.OperationsClient.await":"SpecialWords.Operations.await","specialwords.OperationsClient.awaitWithResponse":"SpecialWords.Operations.await","specialwords.OperationsClient.breakMethod":"SpecialWords.Operations.break","specialwords.OperationsClient.breakMethodWithResponse":"SpecialWords.Operations.break","specialwords.OperationsClient.classMethod":"SpecialWords.Operations.class","specialwords.OperationsClient.classMethodWithResponse":"SpecialWords.Operations.class","specialwords.OperationsClient.constructor":"SpecialWords.Operations.constructor","specialwords.OperationsClient.constructorWithResponse":"SpecialWords.Operations.constructor","specialwords.OperationsClient.continueMethod":"SpecialWords.Operations.continue","specialwords.OperationsClient.continueMethodWithResponse":"SpecialWords.Operations.continue","specialwords.OperationsClient.def":"SpecialWords.Operations.def","specialwords.OperationsClient.defWithResponse":"SpecialWords.Operations.def","specialwords.OperationsClient.del":"SpecialWords.Operations.del","specialwords.OperationsClient.delWithResponse":"SpecialWords.Operations.del","specialwords.OperationsClient.elif":"SpecialWords.Operations.elif","specialwords.OperationsClient.elifWithResponse":"SpecialWords.Operations.elif","specialwords.OperationsClient.elseMethod":"SpecialWords.Operations.else","specialwords.OperationsClient.elseMethodWithResponse":"SpecialWords.Operations.else","specialwords.OperationsClient.except":"SpecialWords.Operations.except","specialwords.OperationsClient.exceptWithResponse":"SpecialWords.Operations.except","specialwords.OperationsClient.exec":"SpecialWords.Operations.exec","specialwords.OperationsClient.execWithResponse":"SpecialWords.Operations.exec","specialwords.OperationsClient.finallyMethod":"SpecialWords.Operations.finally","specialwords.OperationsClient.finallyMethodWithResponse":"SpecialWords.Operations.finally","specialwords.OperationsClient.forMethod":"SpecialWords.Operations.for","specialwords.OperationsClient.forMethodWithResponse":"SpecialWords.Operations.for","specialwords.OperationsClient.from":"SpecialWords.Operations.from","specialwords.OperationsClient.fromWithResponse":"SpecialWords.Operations.from","specialwords.OperationsClient.global":"SpecialWords.Operations.global","specialwords.OperationsClient.globalWithResponse":"SpecialWords.Operations.global","specialwords.OperationsClient.ifMethod":"SpecialWords.Operations.if","specialwords.OperationsClient.ifMethodWithResponse":"SpecialWords.Operations.if","specialwords.OperationsClient.importMethod":"SpecialWords.Operations.import","specialwords.OperationsClient.importMethodWithResponse":"SpecialWords.Operations.import","specialwords.OperationsClient.in":"SpecialWords.Operations.in","specialwords.OperationsClient.inWithResponse":"SpecialWords.Operations.in","specialwords.OperationsClient.is":"SpecialWords.Operations.is","specialwords.OperationsClient.isWithResponse":"SpecialWords.Operations.is","specialwords.OperationsClient.lambda":"SpecialWords.Operations.lambda","specialwords.OperationsClient.lambdaWithResponse":"SpecialWords.Operations.lambda","specialwords.OperationsClient.not":"SpecialWords.Operations.not","specialwords.OperationsClient.notWithResponse":"SpecialWords.Operations.not","specialwords.OperationsClient.or":"SpecialWords.Operations.or","specialwords.OperationsClient.orWithResponse":"SpecialWords.Operations.or","specialwords.OperationsClient.pass":"SpecialWords.Operations.pass","specialwords.OperationsClient.passWithResponse":"SpecialWords.Operations.pass","specialwords.OperationsClient.raise":"SpecialWords.Operations.raise","specialwords.OperationsClient.raiseWithResponse":"SpecialWords.Operations.raise","specialwords.OperationsClient.returnMethod":"SpecialWords.Operations.return","specialwords.OperationsClient.returnMethodWithResponse":"SpecialWords.Operations.return","specialwords.OperationsClient.tryMethod":"SpecialWords.Operations.try","specialwords.OperationsClient.tryMethodWithResponse":"SpecialWords.Operations.try","specialwords.OperationsClient.whileMethod":"SpecialWords.Operations.while","specialwords.OperationsClient.whileMethodWithResponse":"SpecialWords.Operations.while","specialwords.OperationsClient.with":"SpecialWords.Operations.with","specialwords.OperationsClient.withWithResponse":"SpecialWords.Operations.with","specialwords.OperationsClient.yield":"SpecialWords.Operations.yield","specialwords.OperationsClient.yieldWithResponse":"SpecialWords.Operations.yield","specialwords.ParametersAsyncClient":"SpecialWords.Parameters","specialwords.ParametersAsyncClient.withAnd":"SpecialWords.Parameters.withAnd","specialwords.ParametersAsyncClient.withAndWithResponse":"SpecialWords.Parameters.withAnd","specialwords.ParametersAsyncClient.withAs":"SpecialWords.Parameters.withAs","specialwords.ParametersAsyncClient.withAsWithResponse":"SpecialWords.Parameters.withAs","specialwords.ParametersAsyncClient.withAssert":"SpecialWords.Parameters.withAssert","specialwords.ParametersAsyncClient.withAssertWithResponse":"SpecialWords.Parameters.withAssert","specialwords.ParametersAsyncClient.withAsyncWithResponse":"SpecialWords.Parameters.withAsync","specialwords.ParametersAsyncClient.withAwait":"SpecialWords.Parameters.withAwait","specialwords.ParametersAsyncClient.withAwaitWithResponse":"SpecialWords.Parameters.withAwait","specialwords.ParametersAsyncClient.withBreak":"SpecialWords.Parameters.withBreak","specialwords.ParametersAsyncClient.withBreakWithResponse":"SpecialWords.Parameters.withBreak","specialwords.ParametersAsyncClient.withCancellationToken":"SpecialWords.Parameters.withCancellationToken","specialwords.ParametersAsyncClient.withCancellationTokenWithResponse":"SpecialWords.Parameters.withCancellationToken","specialwords.ParametersAsyncClient.withClass":"SpecialWords.Parameters.withClass","specialwords.ParametersAsyncClient.withClassWithResponse":"SpecialWords.Parameters.withClass","specialwords.ParametersAsyncClient.withConstructor":"SpecialWords.Parameters.withConstructor","specialwords.ParametersAsyncClient.withConstructorWithResponse":"SpecialWords.Parameters.withConstructor","specialwords.ParametersAsyncClient.withContinue":"SpecialWords.Parameters.withContinue","specialwords.ParametersAsyncClient.withContinueWithResponse":"SpecialWords.Parameters.withContinue","specialwords.ParametersAsyncClient.withDef":"SpecialWords.Parameters.withDef","specialwords.ParametersAsyncClient.withDefWithResponse":"SpecialWords.Parameters.withDef","specialwords.ParametersAsyncClient.withDel":"SpecialWords.Parameters.withDel","specialwords.ParametersAsyncClient.withDelWithResponse":"SpecialWords.Parameters.withDel","specialwords.ParametersAsyncClient.withElif":"SpecialWords.Parameters.withElif","specialwords.ParametersAsyncClient.withElifWithResponse":"SpecialWords.Parameters.withElif","specialwords.ParametersAsyncClient.withElse":"SpecialWords.Parameters.withElse","specialwords.ParametersAsyncClient.withElseWithResponse":"SpecialWords.Parameters.withElse","specialwords.ParametersAsyncClient.withExcept":"SpecialWords.Parameters.withExcept","specialwords.ParametersAsyncClient.withExceptWithResponse":"SpecialWords.Parameters.withExcept","specialwords.ParametersAsyncClient.withExec":"SpecialWords.Parameters.withExec","specialwords.ParametersAsyncClient.withExecWithResponse":"SpecialWords.Parameters.withExec","specialwords.ParametersAsyncClient.withFinally":"SpecialWords.Parameters.withFinally","specialwords.ParametersAsyncClient.withFinallyWithResponse":"SpecialWords.Parameters.withFinally","specialwords.ParametersAsyncClient.withFor":"SpecialWords.Parameters.withFor","specialwords.ParametersAsyncClient.withForWithResponse":"SpecialWords.Parameters.withFor","specialwords.ParametersAsyncClient.withFrom":"SpecialWords.Parameters.withFrom","specialwords.ParametersAsyncClient.withFromWithResponse":"SpecialWords.Parameters.withFrom","specialwords.ParametersAsyncClient.withGlobal":"SpecialWords.Parameters.withGlobal","specialwords.ParametersAsyncClient.withGlobalWithResponse":"SpecialWords.Parameters.withGlobal","specialwords.ParametersAsyncClient.withIf":"SpecialWords.Parameters.withIf","specialwords.ParametersAsyncClient.withIfWithResponse":"SpecialWords.Parameters.withIf","specialwords.ParametersAsyncClient.withImport":"SpecialWords.Parameters.withImport","specialwords.ParametersAsyncClient.withImportWithResponse":"SpecialWords.Parameters.withImport","specialwords.ParametersAsyncClient.withIn":"SpecialWords.Parameters.withIn","specialwords.ParametersAsyncClient.withInWithResponse":"SpecialWords.Parameters.withIn","specialwords.ParametersAsyncClient.withIs":"SpecialWords.Parameters.withIs","specialwords.ParametersAsyncClient.withIsWithResponse":"SpecialWords.Parameters.withIs","specialwords.ParametersAsyncClient.withLambda":"SpecialWords.Parameters.withLambda","specialwords.ParametersAsyncClient.withLambdaWithResponse":"SpecialWords.Parameters.withLambda","specialwords.ParametersAsyncClient.withNot":"SpecialWords.Parameters.withNot","specialwords.ParametersAsyncClient.withNotWithResponse":"SpecialWords.Parameters.withNot","specialwords.ParametersAsyncClient.withOr":"SpecialWords.Parameters.withOr","specialwords.ParametersAsyncClient.withOrWithResponse":"SpecialWords.Parameters.withOr","specialwords.ParametersAsyncClient.withPass":"SpecialWords.Parameters.withPass","specialwords.ParametersAsyncClient.withPassWithResponse":"SpecialWords.Parameters.withPass","specialwords.ParametersAsyncClient.withRaise":"SpecialWords.Parameters.withRaise","specialwords.ParametersAsyncClient.withRaiseWithResponse":"SpecialWords.Parameters.withRaise","specialwords.ParametersAsyncClient.withReturn":"SpecialWords.Parameters.withReturn","specialwords.ParametersAsyncClient.withReturnWithResponse":"SpecialWords.Parameters.withReturn","specialwords.ParametersAsyncClient.withTry":"SpecialWords.Parameters.withTry","specialwords.ParametersAsyncClient.withTryWithResponse":"SpecialWords.Parameters.withTry","specialwords.ParametersAsyncClient.withWhile":"SpecialWords.Parameters.withWhile","specialwords.ParametersAsyncClient.withWhileWithResponse":"SpecialWords.Parameters.withWhile","specialwords.ParametersAsyncClient.withWith":"SpecialWords.Parameters.withWith","specialwords.ParametersAsyncClient.withWithWithResponse":"SpecialWords.Parameters.withWith","specialwords.ParametersAsyncClient.withYield":"SpecialWords.Parameters.withYield","specialwords.ParametersAsyncClient.withYieldWithResponse":"SpecialWords.Parameters.withYield","specialwords.ParametersClient":"SpecialWords.Parameters","specialwords.ParametersClient.withAnd":"SpecialWords.Parameters.withAnd","specialwords.ParametersClient.withAndWithResponse":"SpecialWords.Parameters.withAnd","specialwords.ParametersClient.withAs":"SpecialWords.Parameters.withAs","specialwords.ParametersClient.withAsWithResponse":"SpecialWords.Parameters.withAs","specialwords.ParametersClient.withAssert":"SpecialWords.Parameters.withAssert","specialwords.ParametersClient.withAssertWithResponse":"SpecialWords.Parameters.withAssert","specialwords.ParametersClient.withAsyncWithResponse":"SpecialWords.Parameters.withAsync","specialwords.ParametersClient.withAwait":"SpecialWords.Parameters.withAwait","specialwords.ParametersClient.withAwaitWithResponse":"SpecialWords.Parameters.withAwait","specialwords.ParametersClient.withBreak":"SpecialWords.Parameters.withBreak","specialwords.ParametersClient.withBreakWithResponse":"SpecialWords.Parameters.withBreak","specialwords.ParametersClient.withCancellationToken":"SpecialWords.Parameters.withCancellationToken","specialwords.ParametersClient.withCancellationTokenWithResponse":"SpecialWords.Parameters.withCancellationToken","specialwords.ParametersClient.withClass":"SpecialWords.Parameters.withClass","specialwords.ParametersClient.withClassWithResponse":"SpecialWords.Parameters.withClass","specialwords.ParametersClient.withConstructor":"SpecialWords.Parameters.withConstructor","specialwords.ParametersClient.withConstructorWithResponse":"SpecialWords.Parameters.withConstructor","specialwords.ParametersClient.withContinue":"SpecialWords.Parameters.withContinue","specialwords.ParametersClient.withContinueWithResponse":"SpecialWords.Parameters.withContinue","specialwords.ParametersClient.withDef":"SpecialWords.Parameters.withDef","specialwords.ParametersClient.withDefWithResponse":"SpecialWords.Parameters.withDef","specialwords.ParametersClient.withDel":"SpecialWords.Parameters.withDel","specialwords.ParametersClient.withDelWithResponse":"SpecialWords.Parameters.withDel","specialwords.ParametersClient.withElif":"SpecialWords.Parameters.withElif","specialwords.ParametersClient.withElifWithResponse":"SpecialWords.Parameters.withElif","specialwords.ParametersClient.withElse":"SpecialWords.Parameters.withElse","specialwords.ParametersClient.withElseWithResponse":"SpecialWords.Parameters.withElse","specialwords.ParametersClient.withExcept":"SpecialWords.Parameters.withExcept","specialwords.ParametersClient.withExceptWithResponse":"SpecialWords.Parameters.withExcept","specialwords.ParametersClient.withExec":"SpecialWords.Parameters.withExec","specialwords.ParametersClient.withExecWithResponse":"SpecialWords.Parameters.withExec","specialwords.ParametersClient.withFinally":"SpecialWords.Parameters.withFinally","specialwords.ParametersClient.withFinallyWithResponse":"SpecialWords.Parameters.withFinally","specialwords.ParametersClient.withFor":"SpecialWords.Parameters.withFor","specialwords.ParametersClient.withForWithResponse":"SpecialWords.Parameters.withFor","specialwords.ParametersClient.withFrom":"SpecialWords.Parameters.withFrom","specialwords.ParametersClient.withFromWithResponse":"SpecialWords.Parameters.withFrom","specialwords.ParametersClient.withGlobal":"SpecialWords.Parameters.withGlobal","specialwords.ParametersClient.withGlobalWithResponse":"SpecialWords.Parameters.withGlobal","specialwords.ParametersClient.withIf":"SpecialWords.Parameters.withIf","specialwords.ParametersClient.withIfWithResponse":"SpecialWords.Parameters.withIf","specialwords.ParametersClient.withImport":"SpecialWords.Parameters.withImport","specialwords.ParametersClient.withImportWithResponse":"SpecialWords.Parameters.withImport","specialwords.ParametersClient.withIn":"SpecialWords.Parameters.withIn","specialwords.ParametersClient.withInWithResponse":"SpecialWords.Parameters.withIn","specialwords.ParametersClient.withIs":"SpecialWords.Parameters.withIs","specialwords.ParametersClient.withIsWithResponse":"SpecialWords.Parameters.withIs","specialwords.ParametersClient.withLambda":"SpecialWords.Parameters.withLambda","specialwords.ParametersClient.withLambdaWithResponse":"SpecialWords.Parameters.withLambda","specialwords.ParametersClient.withNot":"SpecialWords.Parameters.withNot","specialwords.ParametersClient.withNotWithResponse":"SpecialWords.Parameters.withNot","specialwords.ParametersClient.withOr":"SpecialWords.Parameters.withOr","specialwords.ParametersClient.withOrWithResponse":"SpecialWords.Parameters.withOr","specialwords.ParametersClient.withPass":"SpecialWords.Parameters.withPass","specialwords.ParametersClient.withPassWithResponse":"SpecialWords.Parameters.withPass","specialwords.ParametersClient.withRaise":"SpecialWords.Parameters.withRaise","specialwords.ParametersClient.withRaiseWithResponse":"SpecialWords.Parameters.withRaise","specialwords.ParametersClient.withReturn":"SpecialWords.Parameters.withReturn","specialwords.ParametersClient.withReturnWithResponse":"SpecialWords.Parameters.withReturn","specialwords.ParametersClient.withTry":"SpecialWords.Parameters.withTry","specialwords.ParametersClient.withTryWithResponse":"SpecialWords.Parameters.withTry","specialwords.ParametersClient.withWhile":"SpecialWords.Parameters.withWhile","specialwords.ParametersClient.withWhileWithResponse":"SpecialWords.Parameters.withWhile","specialwords.ParametersClient.withWith":"SpecialWords.Parameters.withWith","specialwords.ParametersClient.withWithWithResponse":"SpecialWords.Parameters.withWith","specialwords.ParametersClient.withYield":"SpecialWords.Parameters.withYield","specialwords.ParametersClient.withYieldWithResponse":"SpecialWords.Parameters.withYield","specialwords.SpecialWordsClientBuilder":"SpecialWords","specialwords.modelproperties.models.DictMethods":"SpecialWords.ModelProperties.DictMethods","specialwords.modelproperties.models.SameAsModel":"SpecialWords.ModelProperties.SameAsModel","specialwords.models.models.And":"SpecialWords.Models.and","specialwords.models.models.As":"SpecialWords.Models.as","specialwords.models.models.Assert":"SpecialWords.Models.assert","specialwords.models.models.Async":"SpecialWords.Models.async","specialwords.models.models.Await":"SpecialWords.Models.await","specialwords.models.models.Break":"SpecialWords.Models.break","specialwords.models.models.ClassModel":"SpecialWords.Models.class","specialwords.models.models.Constructor":"SpecialWords.Models.constructor","specialwords.models.models.Continue":"SpecialWords.Models.continue","specialwords.models.models.Def":"SpecialWords.Models.def","specialwords.models.models.Del":"SpecialWords.Models.del","specialwords.models.models.Elif":"SpecialWords.Models.elif","specialwords.models.models.Else":"SpecialWords.Models.else","specialwords.models.models.Except":"SpecialWords.Models.except","specialwords.models.models.Exec":"SpecialWords.Models.exec","specialwords.models.models.Finally":"SpecialWords.Models.finally","specialwords.models.models.For":"SpecialWords.Models.for","specialwords.models.models.From":"SpecialWords.Models.from","specialwords.models.models.Global":"SpecialWords.Models.global","specialwords.models.models.If":"SpecialWords.Models.if","specialwords.models.models.Import":"SpecialWords.Models.import","specialwords.models.models.In":"SpecialWords.Models.in","specialwords.models.models.Is":"SpecialWords.Models.is","specialwords.models.models.Lambda":"SpecialWords.Models.lambda","specialwords.models.models.Not":"SpecialWords.Models.not","specialwords.models.models.Or":"SpecialWords.Models.or","specialwords.models.models.Pass":"SpecialWords.Models.pass","specialwords.models.models.Raise":"SpecialWords.Models.raise","specialwords.models.models.Return":"SpecialWords.Models.return","specialwords.models.models.Try":"SpecialWords.Models.try","specialwords.models.models.While":"SpecialWords.Models.while","specialwords.models.models.With":"SpecialWords.Models.with","specialwords.models.models.Yield":"SpecialWords.Models.yield"},"generatedFiles":["src/main/java/module-info.java","src/main/java/specialwords/ModelPropertiesAsyncClient.java","src/main/java/specialwords/ModelPropertiesClient.java","src/main/java/specialwords/ModelsAsyncClient.java","src/main/java/specialwords/ModelsClient.java","src/main/java/specialwords/OperationsAsyncClient.java","src/main/java/specialwords/OperationsClient.java","src/main/java/specialwords/ParametersAsyncClient.java","src/main/java/specialwords/ParametersClient.java","src/main/java/specialwords/SpecialWordsClientBuilder.java","src/main/java/specialwords/implementation/ModelPropertiesImpl.java","src/main/java/specialwords/implementation/ModelsImpl.java","src/main/java/specialwords/implementation/OperationsImpl.java","src/main/java/specialwords/implementation/ParametersImpl.java","src/main/java/specialwords/implementation/SpecialWordsClientImpl.java","src/main/java/specialwords/implementation/package-info.java","src/main/java/specialwords/modelproperties/models/DictMethods.java","src/main/java/specialwords/modelproperties/models/SameAsModel.java","src/main/java/specialwords/modelproperties/models/package-info.java","src/main/java/specialwords/models/models/And.java","src/main/java/specialwords/models/models/As.java","src/main/java/specialwords/models/models/Assert.java","src/main/java/specialwords/models/models/Async.java","src/main/java/specialwords/models/models/Await.java","src/main/java/specialwords/models/models/Break.java","src/main/java/specialwords/models/models/ClassModel.java","src/main/java/specialwords/models/models/Constructor.java","src/main/java/specialwords/models/models/Continue.java","src/main/java/specialwords/models/models/Def.java","src/main/java/specialwords/models/models/Del.java","src/main/java/specialwords/models/models/Elif.java","src/main/java/specialwords/models/models/Else.java","src/main/java/specialwords/models/models/Except.java","src/main/java/specialwords/models/models/Exec.java","src/main/java/specialwords/models/models/Finally.java","src/main/java/specialwords/models/models/For.java","src/main/java/specialwords/models/models/From.java","src/main/java/specialwords/models/models/Global.java","src/main/java/specialwords/models/models/If.java","src/main/java/specialwords/models/models/Import.java","src/main/java/specialwords/models/models/In.java","src/main/java/specialwords/models/models/Is.java","src/main/java/specialwords/models/models/Lambda.java","src/main/java/specialwords/models/models/Not.java","src/main/java/specialwords/models/models/Or.java","src/main/java/specialwords/models/models/Pass.java","src/main/java/specialwords/models/models/Raise.java","src/main/java/specialwords/models/models/Return.java","src/main/java/specialwords/models/models/Try.java","src/main/java/specialwords/models/models/While.java","src/main/java/specialwords/models/models/With.java","src/main/java/specialwords/models/models/Yield.java","src/main/java/specialwords/models/models/package-info.java","src/main/java/specialwords/package-info.java"]} \ No newline at end of file diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/resources/documentation.properties b/packages/http-client-java/generator/http-client-generator-test/src/main/resources/documentation.properties new file mode 100644 index 00000000000..ca812989b4f --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/resources/documentation.properties @@ -0,0 +1,2 @@ +name=${project.artifactId} +version=${project.version} diff --git a/packages/http-client-java/generator/http-client-generator-test/src/main/resources/encode-array.properties b/packages/http-client-java/generator/http-client-generator-test/src/main/resources/encode-array.properties new file mode 100644 index 00000000000..ca812989b4f --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/main/resources/encode-array.properties @@ -0,0 +1,2 @@ +name=${project.artifactId} +version=${project.version} diff --git a/packages/http-client-java/generator/http-client-generator-test/src/test/java/documentation/generated/DocumentationClientTestBase.java b/packages/http-client-java/generator/http-client-generator-test/src/test/java/documentation/generated/DocumentationClientTestBase.java new file mode 100644 index 00000000000..21b8d2c836b --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/test/java/documentation/generated/DocumentationClientTestBase.java @@ -0,0 +1,46 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package documentation.generated; + +// The Java test files under 'generated' package are generated for your reference. +// If you wish to modify these files, please copy them out of the 'generated' package, and modify there. +// See https://aka.ms/azsdk/dpg/java/tests for guide on adding a test. + +import com.azure.core.http.policy.HttpLogDetailLevel; +import com.azure.core.http.policy.HttpLogOptions; +import com.azure.core.test.TestMode; +import com.azure.core.test.TestProxyTestBase; +import com.azure.core.util.Configuration; +import documentation.DocumentationClientBuilder; +import documentation.ListsClient; +import documentation.TextFormattingClient; + +class DocumentationClientTestBase extends TestProxyTestBase { + protected ListsClient listsClient; + + protected TextFormattingClient textFormattingClient; + + @Override + protected void beforeTest() { + DocumentationClientBuilder listsClientbuilder = new DocumentationClientBuilder() + .endpoint(Configuration.getGlobalConfiguration().get("ENDPOINT", "http://localhost:3000")) + .httpClient(getHttpClientOrUsePlayback(getHttpClients().findFirst().orElse(null))) + .httpLogOptions(new HttpLogOptions().setLogLevel(HttpLogDetailLevel.BASIC)); + if (getTestMode() == TestMode.RECORD) { + listsClientbuilder.addPolicy(interceptorManager.getRecordPolicy()); + } + listsClient = listsClientbuilder.buildListsClient(); + + DocumentationClientBuilder textFormattingClientbuilder = new DocumentationClientBuilder() + .endpoint(Configuration.getGlobalConfiguration().get("ENDPOINT", "http://localhost:3000")) + .httpClient(getHttpClientOrUsePlayback(getHttpClients().findFirst().orElse(null))) + .httpLogOptions(new HttpLogOptions().setLogLevel(HttpLogDetailLevel.BASIC)); + if (getTestMode() == TestMode.RECORD) { + textFormattingClientbuilder.addPolicy(interceptorManager.getRecordPolicy()); + } + textFormattingClient = textFormattingClientbuilder.buildTextFormattingClient(); + + } +} diff --git a/packages/http-client-java/generator/http-client-generator-test/src/test/java/encode/array/generated/ArrayClientTestBase.java b/packages/http-client-java/generator/http-client-generator-test/src/test/java/encode/array/generated/ArrayClientTestBase.java new file mode 100644 index 00000000000..225f9f2497e --- /dev/null +++ b/packages/http-client-java/generator/http-client-generator-test/src/test/java/encode/array/generated/ArrayClientTestBase.java @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package encode.array.generated; + +// The Java test files under 'generated' package are generated for your reference. +// If you wish to modify these files, please copy them out of the 'generated' package, and modify there. +// See https://aka.ms/azsdk/dpg/java/tests for guide on adding a test. + +import com.azure.core.http.policy.HttpLogDetailLevel; +import com.azure.core.http.policy.HttpLogOptions; +import com.azure.core.test.TestMode; +import com.azure.core.test.TestProxyTestBase; +import com.azure.core.util.Configuration; +import encode.array.ArrayClient; +import encode.array.ArrayClientBuilder; + +class ArrayClientTestBase extends TestProxyTestBase { + protected ArrayClient arrayClient; + + @Override + protected void beforeTest() { + ArrayClientBuilder arrayClientbuilder = new ArrayClientBuilder() + .endpoint(Configuration.getGlobalConfiguration().get("ENDPOINT", "http://localhost:3000")) + .httpClient(getHttpClientOrUsePlayback(getHttpClients().findFirst().orElse(null))) + .httpLogOptions(new HttpLogOptions().setLogLevel(HttpLogDetailLevel.BASIC)); + if (getTestMode() == TestMode.RECORD) { + arrayClientbuilder.addPolicy(interceptorManager.getRecordPolicy()); + } + arrayClient = arrayClientbuilder.buildClient(); + + } +} diff --git a/packages/http-client-java/package-lock.json b/packages/http-client-java/package-lock.json index 8274f740ed9..710a31da7e6 100644 --- a/packages/http-client-java/package-lock.json +++ b/packages/http-client-java/package-lock.json @@ -1,12 +1,12 @@ { "name": "@typespec/http-client-java", - "version": "0.6.0", + "version": "0.6.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@typespec/http-client-java", - "version": "0.6.0", + "version": "0.6.1", "license": "MIT", "dependencies": { "@autorest/codemodel": "~4.20.1", @@ -14,26 +14,26 @@ "lodash": "~4.17.21" }, "devDependencies": { - "@azure-tools/typespec-autorest": "0.62.0", - "@azure-tools/typespec-azure-core": "0.62.0", - "@azure-tools/typespec-azure-resource-manager": "0.62.1", - "@azure-tools/typespec-azure-rulesets": "0.62.0", - "@azure-tools/typespec-client-generator-core": "0.62.0", + "@azure-tools/typespec-autorest": "0.63.0", + "@azure-tools/typespec-azure-core": "0.63.0", + "@azure-tools/typespec-azure-resource-manager": "0.63.0", + "@azure-tools/typespec-azure-rulesets": "0.63.0", + "@azure-tools/typespec-client-generator-core": "0.63.0", "@microsoft/api-extractor": "^7.55.1", "@microsoft/api-extractor-model": "^7.32.1", "@types/js-yaml": "~4.0.9", "@types/lodash": "~4.17.21", "@types/node": "~24.10.1", - "@typespec/compiler": "1.6.0", - "@typespec/events": "0.76.0", - "@typespec/http": "1.6.0", - "@typespec/openapi": "1.6.0", - "@typespec/rest": "0.76.0", - "@typespec/spector": "0.1.0-alpha.20", - "@typespec/sse": "0.76.0", - "@typespec/streams": "0.76.0", - "@typespec/versioning": "0.76.0", - "@typespec/xml": "0.76.0", + "@typespec/compiler": "1.7.0", + "@typespec/events": "0.77.0", + "@typespec/http": "1.7.0", + "@typespec/openapi": "1.7.0", + "@typespec/rest": "0.77.0", + "@typespec/spector": "0.1.0-alpha.21", + "@typespec/sse": "0.77.0", + "@typespec/streams": "0.77.0", + "@typespec/versioning": "0.77.0", + "@typespec/xml": "0.77.0", "@vitest/coverage-v8": "^4.0.14", "@vitest/ui": "^4.0.14", "c8": "~10.1.3", @@ -45,19 +45,19 @@ "node": ">=20.0.0" }, "peerDependencies": { - "@azure-tools/typespec-autorest": ">=0.62.0 <1.0.0", - "@azure-tools/typespec-azure-core": ">=0.62.0 <1.0.0", - "@azure-tools/typespec-azure-resource-manager": ">=0.62.1 <1.0.0", - "@azure-tools/typespec-client-generator-core": ">=0.62.0 <1.0.0", - "@typespec/compiler": "^1.6.0", - "@typespec/events": ">=0.76.0 <1.0.0", - "@typespec/http": "^1.6.0", - "@typespec/openapi": "^1.6.0", - "@typespec/rest": ">=0.76.0 <1.0.0", - "@typespec/sse": ">=0.76.0 <1.0.0", - "@typespec/streams": ">=0.76.0 <1.0.0", - "@typespec/versioning": ">=0.76.0 <1.0.0", - "@typespec/xml": ">=0.76.0 <1.0.0" + "@azure-tools/typespec-autorest": ">=0.63.0 <1.0.0", + "@azure-tools/typespec-azure-core": ">=0.63.0 <1.0.0", + "@azure-tools/typespec-azure-resource-manager": ">=0.63.0 <1.0.0", + "@azure-tools/typespec-client-generator-core": ">=0.63.0 <1.0.0", + "@typespec/compiler": "^1.7.0", + "@typespec/events": ">=0.77.0 <1.0.0", + "@typespec/http": "^1.7.0", + "@typespec/openapi": "^1.7.0", + "@typespec/rest": ">=0.77.0 <1.0.0", + "@typespec/sse": ">=0.77.0 <1.0.0", + "@typespec/streams": ">=0.77.0 <1.0.0", + "@typespec/versioning": ">=0.77.0 <1.0.0", + "@typespec/xml": ">=0.77.0 <1.0.0" } }, "node_modules/@autorest/codemodel": { @@ -110,24 +110,24 @@ } }, "node_modules/@azure-tools/typespec-autorest": { - "version": "0.62.0", - "resolved": "https://registry.npmjs.org/@azure-tools/typespec-autorest/-/typespec-autorest-0.62.0.tgz", - "integrity": "sha512-XftwipfGGMk9e3qGzbRMBvVpfIqLMJKc8H+XlPHFymnCfexBniZn4Qu2t8nzOVM9fgOoFDjNDzk8W5lf59U5Dg==", + "version": "0.63.0", + "resolved": "https://registry.npmjs.org/@azure-tools/typespec-autorest/-/typespec-autorest-0.63.0.tgz", + "integrity": "sha512-E04eX5axqua+bVs8QH1z74Wrq+XjO6tInq6d6EhjBNQAcRyFCJNxJHqcJkzMWNy1ID/iIGNXyRG/elK2AdegZg==", "dev": true, "license": "MIT", "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@azure-tools/typespec-azure-core": "^0.62.0", - "@azure-tools/typespec-azure-resource-manager": "^0.62.0", - "@azure-tools/typespec-client-generator-core": "^0.62.0", - "@typespec/compiler": "^1.6.0", - "@typespec/http": "^1.6.0", - "@typespec/openapi": "^1.6.0", - "@typespec/rest": "^0.76.0", - "@typespec/versioning": "^0.76.0", - "@typespec/xml": "^0.76.0" + "@azure-tools/typespec-azure-core": "^0.63.0", + "@azure-tools/typespec-azure-resource-manager": "^0.63.0", + "@azure-tools/typespec-client-generator-core": "^0.63.0", + "@typespec/compiler": "^1.7.0", + "@typespec/http": "^1.7.0", + "@typespec/openapi": "^1.7.0", + "@typespec/rest": "^0.77.0", + "@typespec/versioning": "^0.77.0", + "@typespec/xml": "^0.77.0" }, "peerDependenciesMeta": { "@typespec/xml": { @@ -136,24 +136,24 @@ } }, "node_modules/@azure-tools/typespec-azure-core": { - "version": "0.62.0", - "resolved": "https://registry.npmjs.org/@azure-tools/typespec-azure-core/-/typespec-azure-core-0.62.0.tgz", - "integrity": "sha512-4LIFqNHhKO1/jiCH0U2rfI+yH7vkWcFuwpjNyRTWXw/YghAI2d+aIEwtT4oM8jWeYR3KUQfA6AqGPRCm90AXYA==", + "version": "0.63.0", + "resolved": "https://registry.npmjs.org/@azure-tools/typespec-azure-core/-/typespec-azure-core-0.63.0.tgz", + "integrity": "sha512-FbEmpZSQENzBt/Y8qSF1b98T8CqT3bV7IRV8AGGm/73NQZiWQCm2LvQzR0/lbqGntS2EnSBrt394Kt69wM4ifA==", "dev": true, "license": "MIT", "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.6.0", - "@typespec/http": "^1.6.0", - "@typespec/rest": "^0.76.0" + "@typespec/compiler": "^1.7.0", + "@typespec/http": "^1.7.0", + "@typespec/rest": "^0.77.0" } }, "node_modules/@azure-tools/typespec-azure-resource-manager": { - "version": "0.62.1", - "resolved": "https://registry.npmjs.org/@azure-tools/typespec-azure-resource-manager/-/typespec-azure-resource-manager-0.62.1.tgz", - "integrity": "sha512-sbCwg5Auvm2/fYUWbx3RlQyZGlMoAmhtRjrurgwWzZIBxBJ7sVqgUQktl3WGHAoeJ3qYa2gAIL4j8/xSPwt5kw==", + "version": "0.63.0", + "resolved": "https://registry.npmjs.org/@azure-tools/typespec-azure-resource-manager/-/typespec-azure-resource-manager-0.63.0.tgz", + "integrity": "sha512-QXHryXgV9Rh7lBW9hrehjdGVM/W8eBN6wnfRRZtAAyfTc1AkRGDKOMFBtRtfbEkQpur16mgQTd7EyH2tpqfuSw==", "dev": true, "license": "MIT", "dependencies": { @@ -164,34 +164,34 @@ "node": ">=20.0.0" }, "peerDependencies": { - "@azure-tools/typespec-azure-core": "^0.62.0", - "@typespec/compiler": "^1.6.0", - "@typespec/http": "^1.6.0", - "@typespec/openapi": "^1.6.0", - "@typespec/rest": "^0.76.0", - "@typespec/versioning": "^0.76.0" + "@azure-tools/typespec-azure-core": "^0.63.0", + "@typespec/compiler": "^1.7.0", + "@typespec/http": "^1.7.0", + "@typespec/openapi": "^1.7.0", + "@typespec/rest": "^0.77.0", + "@typespec/versioning": "^0.77.0" } }, "node_modules/@azure-tools/typespec-azure-rulesets": { - "version": "0.62.0", - "resolved": "https://registry.npmjs.org/@azure-tools/typespec-azure-rulesets/-/typespec-azure-rulesets-0.62.0.tgz", - "integrity": "sha512-jEsR9ogSYkYxcOc5biEKbwbYS77ffD8avjT8Sbf5r+8VMPZj46uK3V0FaySbtPh+EEgoBrVj2jcbGGKDFrse1A==", + "version": "0.63.0", + "resolved": "https://registry.npmjs.org/@azure-tools/typespec-azure-rulesets/-/typespec-azure-rulesets-0.63.0.tgz", + "integrity": "sha512-oZSderD/MVnPH+W8hh3rsta1uF9xVLp9b2jjyhiHL9lqYGnHUYk8sDti5PUk/LXIz8QAsBMSbXJMDgxTeND8Kg==", "dev": true, "license": "MIT", "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@azure-tools/typespec-azure-core": "^0.62.0", - "@azure-tools/typespec-azure-resource-manager": "^0.62.0", - "@azure-tools/typespec-client-generator-core": "^0.62.0", - "@typespec/compiler": "^1.6.0" + "@azure-tools/typespec-azure-core": "^0.63.0", + "@azure-tools/typespec-azure-resource-manager": "^0.63.0", + "@azure-tools/typespec-client-generator-core": "^0.63.0", + "@typespec/compiler": "^1.7.0" } }, "node_modules/@azure-tools/typespec-client-generator-core": { - "version": "0.62.0", - "resolved": "https://registry.npmjs.org/@azure-tools/typespec-client-generator-core/-/typespec-client-generator-core-0.62.0.tgz", - "integrity": "sha512-fZilNfvqIW6Jzb97SuM5f+i9p5b0261InQRbQcTbeuYGtb5z5M0v8tuGglE4adU8NqQ1OmEv/oRjQjSeSjlxwA==", + "version": "0.63.0", + "resolved": "https://registry.npmjs.org/@azure-tools/typespec-client-generator-core/-/typespec-client-generator-core-0.63.0.tgz", + "integrity": "sha512-zpvFvjCjNW+GWzHBV7vJ2E1PKXrmyNqp7FQiYo/D7PJBVTXNtOyIKqqo043ktAaWihbr8cl5QguuNSoBAKL0+Q==", "dev": true, "license": "MIT", "dependencies": { @@ -203,16 +203,16 @@ "node": ">=20.0.0" }, "peerDependencies": { - "@azure-tools/typespec-azure-core": "^0.62.0", - "@typespec/compiler": "^1.6.0", - "@typespec/events": "^0.76.0", - "@typespec/http": "^1.6.0", - "@typespec/openapi": "^1.6.0", - "@typespec/rest": "^0.76.0", - "@typespec/sse": "^0.76.0", - "@typespec/streams": "^0.76.0", - "@typespec/versioning": "^0.76.0", - "@typespec/xml": "^0.76.0" + "@azure-tools/typespec-azure-core": "^0.63.0", + "@typespec/compiler": "^1.7.0", + "@typespec/events": "^0.77.0", + "@typespec/http": "^1.7.0", + "@typespec/openapi": "^1.7.0", + "@typespec/rest": "^0.77.0", + "@typespec/sse": "^0.77.0", + "@typespec/streams": "^0.77.0", + "@typespec/versioning": "^0.77.0", + "@typespec/xml": "^0.77.0" } }, "node_modules/@azure/abort-controller": { @@ -405,22 +405,22 @@ } }, "node_modules/@azure/msal-browser": { - "version": "4.26.1", - "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-4.26.1.tgz", - "integrity": "sha512-GGCIsZXxyNm5QcQZ4maA9q+9UWmM+/87G+ybvPkrE32el1URSa9WYt0t67ks3/P0gspZX9RoEqyLqJ/X/JDnBQ==", + "version": "4.27.0", + "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-4.27.0.tgz", + "integrity": "sha512-bZ8Pta6YAbdd0o0PEaL1/geBsPrLEnyY/RDWqvF1PP9RUH8EMLvUMGoZFYS6jSlUan6KZ9IMTLCnwpWWpQRK/w==", "dev": true, "license": "MIT", "dependencies": { - "@azure/msal-common": "15.13.1" + "@azure/msal-common": "15.13.3" }, "engines": { "node": ">=0.8.0" } }, "node_modules/@azure/msal-common": { - "version": "15.13.1", - "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-15.13.1.tgz", - "integrity": "sha512-vQYQcG4J43UWgo1lj7LcmdsGUKWYo28RfEvDQAEMmQIMjSFufvb+pS0FJ3KXmrPmnWlt1vHDl3oip6mIDUQ4uA==", + "version": "15.13.3", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-15.13.3.tgz", + "integrity": "sha512-shSDU7Ioecya+Aob5xliW9IGq1Ui8y4EVSdWGyI1Gbm4Vg61WpP95LuzcY214/wEjSn6w4PZYD4/iVldErHayQ==", "dev": true, "license": "MIT", "engines": { @@ -428,13 +428,13 @@ } }, "node_modules/@azure/msal-node": { - "version": "3.8.2", - "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-3.8.2.tgz", - "integrity": "sha512-dQrex2LiXwlCe9WuBHnCsY+xxLyuMXSd2SDEYJuhqB7cE8u6QafiC1xy8j8eBjGO30AsRi2M6amH0ZKk7vJpjA==", + "version": "3.8.4", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-3.8.4.tgz", + "integrity": "sha512-lvuAwsDpPDE/jSuVQOBMpLbXuVuLsPNRwWCyK3/6bPlBk0fGWegqoZ0qjZclMWyQ2JNvIY3vHY7hoFmFmFQcOw==", "dev": true, "license": "MIT", "dependencies": { - "@azure/msal-common": "15.13.1", + "@azure/msal-common": "15.13.3", "jsonwebtoken": "^9.0.0", "uuid": "^8.3.0" }, @@ -1006,21 +1006,30 @@ "node": ">=18" } }, + "node_modules/@inquirer/ansi": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-2.0.2.tgz", + "integrity": "sha512-SYLX05PwJVnW+WVegZt1T4Ip1qba1ik+pNJPDiqvk6zS5Y/i8PhRzLpGEtVd7sW0G8cMtkD8t4AZYhQwm8vnww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + } + }, "node_modules/@inquirer/checkbox": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.1.4.tgz", - "integrity": "sha512-d30576EZdApjAMceijXA5jDzRQHT/MygbC+J8I7EqA6f/FRpYxlRtRJbHF8gHeWYeSdOuTEJqonn7QLB1ELezA==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-5.0.2.tgz", + "integrity": "sha512-iTPV4tMMct7iOpwer5qmTP7gjnk1VQJjsNfAaC2b8Q3qiuHM3K2yjjDr5u1MKfkrvp2JD4Flf8sIPpF21pmZmw==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.9", - "@inquirer/figures": "^1.0.11", - "@inquirer/type": "^3.0.5", - "ansi-escapes": "^4.3.2", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/ansi": "^2.0.2", + "@inquirer/core": "^11.0.2", + "@inquirer/figures": "^2.0.2", + "@inquirer/type": "^4.0.2" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -1032,17 +1041,17 @@ } }, "node_modules/@inquirer/confirm": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.8.tgz", - "integrity": "sha512-dNLWCYZvXDjO3rnQfk2iuJNL4Ivwz/T2+C3+WnNfJKsNGSuOs3wAo2F6e0p946gtSAk31nZMfW+MRmYaplPKsg==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-6.0.2.tgz", + "integrity": "sha512-A0/13Wyi+8iFeNDX6D4zZYKPoBLIEbE4K/219qHcnpXMer2weWvaTo63+2c7mQPPA206DEMSYVOPnEw3meOlCw==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.9", - "@inquirer/type": "^3.0.5" + "@inquirer/core": "^11.0.2", + "@inquirer/type": "^4.0.2" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -1054,23 +1063,22 @@ } }, "node_modules/@inquirer/core": { - "version": "10.1.15", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.1.15.tgz", - "integrity": "sha512-8xrp836RZvKkpNbVvgWUlxjT4CraKk2q+I3Ksy+seI2zkcE+y6wNs1BVhgcv8VyImFecUhdQrYLdW32pAjwBdA==", + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-11.0.2.tgz", + "integrity": "sha512-lgMRx/n02ciiNELBvFLHtmcjbV5tf5D/I0UYfCg2YbTZWmBZ10/niLd3IjWBxz8LtM27xP+4oLEa06Slmb7p7A==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/figures": "^1.0.13", - "@inquirer/type": "^3.0.8", - "ansi-escapes": "^4.3.2", + "@inquirer/ansi": "^2.0.2", + "@inquirer/figures": "^2.0.2", + "@inquirer/type": "^4.0.2", "cli-width": "^4.1.0", - "mute-stream": "^2.0.0", + "mute-stream": "^3.0.0", "signal-exit": "^4.1.0", - "wrap-ansi": "^6.2.0", - "yoctocolors-cjs": "^2.1.2" + "wrap-ansi": "^9.0.2" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -1081,34 +1089,104 @@ } } }, + "node_modules/@inquirer/core/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@inquirer/core/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@inquirer/core/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@inquirer/core/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@inquirer/core/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/@inquirer/core/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, "node_modules/@inquirer/editor": { - "version": "4.2.16", - "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.16.tgz", - "integrity": "sha512-iSzLjT4C6YKp2DU0fr8T7a97FnRRxMO6CushJnW5ktxLNM2iNeuyUuUA5255eOLPORoGYCrVnuDOEBdGkHGkpw==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-5.0.2.tgz", + "integrity": "sha512-pXQ4Nf0qmFcJuYB6NlcIIxH6l6zKOwNg1Jh/ZRdKd2dTqBB4OXKUFbFwR2K4LVXVtq15ZFFatBVT+rerYR8hWQ==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.15", - "@inquirer/external-editor": "^1.0.0", - "@inquirer/type": "^3.0.8" + "@inquirer/core": "^11.0.2", + "@inquirer/external-editor": "^2.0.2", + "@inquirer/type": "^4.0.2" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -1120,18 +1198,17 @@ } }, "node_modules/@inquirer/expand": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.11.tgz", - "integrity": "sha512-OZSUW4hFMW2TYvX/Sv+NnOZgO8CHT2TU1roUCUIF2T+wfw60XFRRp9MRUPCT06cRnKL+aemt2YmTWwt7rOrNEA==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-5.0.2.tgz", + "integrity": "sha512-siFG1swxfjFIOxIcehtZkh+KUNB/YCpyfHNEGu+nC/SBXIbgUWibvThLn/WesSxLRGOeSKdNKoTm+GQCKFm6Ww==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.9", - "@inquirer/type": "^3.0.5", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/core": "^11.0.2", + "@inquirer/type": "^4.0.2" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -1143,44 +1220,49 @@ } }, "node_modules/@inquirer/external-editor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.0.tgz", - "integrity": "sha512-5v3YXc5ZMfL6OJqXPrX9csb4l7NlQA2doO1yynUjpUChT9hg4JcuBVP0RbsEJ/3SL/sxWEyFjT2W69ZhtoBWqg==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-2.0.2.tgz", + "integrity": "sha512-X/fMXK7vXomRWEex1j8mnj7s1mpnTeP4CO/h2gysJhHLT2WjBnLv4ZQEGpm/kcYI8QfLZ2fgW+9kTKD+jeopLg==", "dev": true, "license": "MIT", "dependencies": { - "chardet": "^2.1.0", - "iconv-lite": "^0.6.3" + "chardet": "^2.1.1", + "iconv-lite": "^0.7.0" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, "node_modules/@inquirer/figures": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.13.tgz", - "integrity": "sha512-lGPVU3yO9ZNqA7vTYz26jny41lE7yoQansmqdMLBEfqaGsmdg7V3W9mK9Pvb5IL4EVZ9GnSDGMO/cJXud5dMaw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-2.0.2.tgz", + "integrity": "sha512-qXm6EVvQx/FmnSrCWCIGtMHwqeLgxABP8XgcaAoywsL0NFga9gD5kfG0gXiv80GjK9Hsoz4pgGwF/+CjygyV9A==", "dev": true, "license": "MIT", "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" } }, "node_modules/@inquirer/input": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.1.8.tgz", - "integrity": "sha512-WXJI16oOZ3/LiENCAxe8joniNp8MQxF6Wi5V+EBbVA0ZIOpFcL4I9e7f7cXse0HJeIPCWO8Lcgnk98juItCi7Q==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-5.0.2.tgz", + "integrity": "sha512-hN2YRo1QiEc9lD3mK+CPnTS4TK2RhCMmMmP4nCWwTkmQL2vx9jPJWYk+rbUZpwR1D583ZJk1FI3i9JZXIpi/qg==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.9", - "@inquirer/type": "^3.0.5" + "@inquirer/core": "^11.0.2", + "@inquirer/type": "^4.0.2" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -1192,17 +1274,17 @@ } }, "node_modules/@inquirer/number": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.11.tgz", - "integrity": "sha512-pQK68CsKOgwvU2eA53AG/4npRTH2pvs/pZ2bFvzpBhrznh8Mcwt19c+nMO7LHRr3Vreu1KPhNBF3vQAKrjIulw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-4.0.2.tgz", + "integrity": "sha512-4McnjTSYrlthNW1ojkkmP75WLRYhQs7GXm6pDDoIrHqJuV5uUYwfdbB0geHdaKMarAqJQgoOVjzIT0jdWCsKew==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.9", - "@inquirer/type": "^3.0.5" + "@inquirer/core": "^11.0.2", + "@inquirer/type": "^4.0.2" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -1214,18 +1296,18 @@ } }, "node_modules/@inquirer/password": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.11.tgz", - "integrity": "sha512-dH6zLdv+HEv1nBs96Case6eppkRggMe8LoOTl30+Gq5Wf27AO/vHFgStTVz4aoevLdNXqwE23++IXGw4eiOXTg==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-5.0.2.tgz", + "integrity": "sha512-oSDziMKiw4G2e4zS+0JRfxuPFFGh6N/9yUaluMgEHp2/Yyj2JGwfDO7XbwtOrxVrz+XsP/iaGyWXdQb9d8A0+g==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.9", - "@inquirer/type": "^3.0.5", - "ansi-escapes": "^4.3.2" + "@inquirer/ansi": "^2.0.2", + "@inquirer/core": "^11.0.2", + "@inquirer/type": "^4.0.2" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -1237,25 +1319,25 @@ } }, "node_modules/@inquirer/prompts": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.4.0.tgz", - "integrity": "sha512-EZiJidQOT4O5PYtqnu1JbF0clv36oW2CviR66c7ma4LsupmmQlUwmdReGKRp456OWPWMz3PdrPiYg3aCk3op2w==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-8.0.2.tgz", + "integrity": "sha512-2zK5zY48fZcl6+gG4eqOC/UzZsJckHCRvjXoLuW4D8LKOCVGdcJiSKkLnumSZjR/6PXPINDGOrGHqNxb+sxJDg==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/checkbox": "^4.1.4", - "@inquirer/confirm": "^5.1.8", - "@inquirer/editor": "^4.2.9", - "@inquirer/expand": "^4.0.11", - "@inquirer/input": "^4.1.8", - "@inquirer/number": "^3.0.11", - "@inquirer/password": "^4.0.11", - "@inquirer/rawlist": "^4.0.11", - "@inquirer/search": "^3.0.11", - "@inquirer/select": "^4.1.0" + "@inquirer/checkbox": "^5.0.2", + "@inquirer/confirm": "^6.0.2", + "@inquirer/editor": "^5.0.2", + "@inquirer/expand": "^5.0.2", + "@inquirer/input": "^5.0.2", + "@inquirer/number": "^4.0.2", + "@inquirer/password": "^5.0.2", + "@inquirer/rawlist": "^5.0.2", + "@inquirer/search": "^4.0.2", + "@inquirer/select": "^5.0.2" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -1267,18 +1349,17 @@ } }, "node_modules/@inquirer/rawlist": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.0.11.tgz", - "integrity": "sha512-uAYtTx0IF/PqUAvsRrF3xvnxJV516wmR6YVONOmCWJbbt87HcDHLfL9wmBQFbNJRv5kCjdYKrZcavDkH3sVJPg==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-5.0.2.tgz", + "integrity": "sha512-AcNALEdQKUQDeJcpC1a3YC53m1MLv+sMUS+vRZ8Qigs1Yg3Dcdtmi82rscJplogKOY8CXkKW4wvVwHS2ZjCIBQ==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.9", - "@inquirer/type": "^3.0.5", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/core": "^11.0.2", + "@inquirer/type": "^4.0.2" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -1290,19 +1371,18 @@ } }, "node_modules/@inquirer/search": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.0.11.tgz", - "integrity": "sha512-9CWQT0ikYcg6Ls3TOa7jljsD7PgjcsYEM0bYE+Gkz+uoW9u8eaJCRHJKkucpRE5+xKtaaDbrND+nPDoxzjYyew==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-4.0.2.tgz", + "integrity": "sha512-hg63w5toohdzE65S3LiGhdfIL0kT+yisbZARf7zw65PvyMUTutTN3eMAvD/B6y/25z88vTrB7kSB45Vz5CbrXg==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.9", - "@inquirer/figures": "^1.0.11", - "@inquirer/type": "^3.0.5", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/core": "^11.0.2", + "@inquirer/figures": "^2.0.2", + "@inquirer/type": "^4.0.2" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -1314,20 +1394,19 @@ } }, "node_modules/@inquirer/select": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.1.0.tgz", - "integrity": "sha512-z0a2fmgTSRN+YBuiK1ROfJ2Nvrpij5lVN3gPDkQGhavdvIVGHGW29LwYZfM/j42Ai2hUghTI/uoBuTbrJk42bA==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-5.0.2.tgz", + "integrity": "sha512-JygTohvQxSNnvt7IKANVlg/eds+yN5sLRilYeGc4ri/9Aqi/2QPoXBMV5Cz/L1VtQv63SnTbPXJZeCK2pSwsOA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.9", - "@inquirer/figures": "^1.0.11", - "@inquirer/type": "^3.0.5", - "ansi-escapes": "^4.3.2", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/ansi": "^2.0.2", + "@inquirer/core": "^11.0.2", + "@inquirer/figures": "^2.0.2", + "@inquirer/type": "^4.0.2" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -1339,13 +1418,13 @@ } }, "node_modules/@inquirer/type": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.8.tgz", - "integrity": "sha512-lg9Whz8onIHRthWaN1Q9EGLa/0LFJjyM8mEUbL1eTi6yMGvBf8gvyDLtxSXztQsxMvhxxNpJYrwa1YHdq+w4Jw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.0.2.tgz", + "integrity": "sha512-cae7mzluplsjSdgFA6ACLygb5jC8alO0UUnFPyu0E7tNRPrL+q/f8VcSXp+cjZQ7l5CMpDpi2G1+IQvkOiL1Lw==", "dev": true, "license": "MIT", "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -2208,18 +2287,18 @@ } }, "node_modules/@typespec/compiler": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@typespec/compiler/-/compiler-1.6.0.tgz", - "integrity": "sha512-yxyV+ch8tnqiuU2gClv/mQEESoFwpkjo6177UkYfV0nVA9PzTg4zVVc7+WIMZk04wiLRRT3H1uc11FB1cwLY3g==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@typespec/compiler/-/compiler-1.7.0.tgz", + "integrity": "sha512-KE2t5I7u/33M/nsIxdng06FUPrqaGSbMsSEsv51eMwYnj3v1+Z3qTTX/dxHAXRXHcfadNlX/NtyAKju+pkMTFQ==", "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "~7.27.1", - "@inquirer/prompts": "^7.4.0", + "@inquirer/prompts": "^8.0.1", "ajv": "~8.17.1", "change-case": "~5.4.4", "env-paths": "^3.0.0", - "globby": "~15.0.0", + "globby": "~16.0.0", "is-unicode-supported": "^2.1.0", "mustache": "~4.2.0", "picocolors": "~1.1.1", @@ -2385,30 +2464,30 @@ } }, "node_modules/@typespec/events": { - "version": "0.76.0", - "resolved": "https://registry.npmjs.org/@typespec/events/-/events-0.76.0.tgz", - "integrity": "sha512-mdjYQ5HA3Y4ZeyAEmiIDdRa9hbc/5qey5hU9UCA0gL+YWVYgoqLPbZQQTwqq3smM35+5cWp9GTGPyNHcOoRwOA==", + "version": "0.77.0", + "resolved": "https://registry.npmjs.org/@typespec/events/-/events-0.77.0.tgz", + "integrity": "sha512-NbOzi7axEt/xGgXaLjcGGV2HjQKNFjbvsQpCeDA6loUghZDK5+5ik/jwMumeUDunoBsAKF78ZxVF5qhQh56dGA==", "dev": true, "license": "MIT", "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.6.0" + "@typespec/compiler": "^1.7.0" } }, "node_modules/@typespec/http": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@typespec/http/-/http-1.6.0.tgz", - "integrity": "sha512-q/JwVw21CF4buE3ZS+xSoy2TKAOwyhZ7g3kdNqCgm69BI5p5GGu+3ZlUA+4Blk8hkt0G8XcIN8fhJP+a4O6KAw==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@typespec/http/-/http-1.7.0.tgz", + "integrity": "sha512-4cGkcMiob3bedWbFkRcq614TDH7WPEI3YMgrg44mBarj903arpEniAESIhNUbLQzQFFc5rOJagexQDl4agVDyA==", "dev": true, "license": "MIT", "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.6.0", - "@typespec/streams": "^0.76.0" + "@typespec/compiler": "^1.7.0", + "@typespec/streams": "^0.77.0" }, "peerDependenciesMeta": { "@typespec/streams": { @@ -2417,37 +2496,37 @@ } }, "node_modules/@typespec/openapi": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@typespec/openapi/-/openapi-1.6.0.tgz", - "integrity": "sha512-KuxYAzfP5ljM0PUhSGclNZgTG0H+kyTQcwn6cf4TKhO72R2QMQmiMtN2plqvzsfkL+TLwad1iZhMWTCAMFAQ4w==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@typespec/openapi/-/openapi-1.7.0.tgz", + "integrity": "sha512-tEAIgGnjLvOjbGAoCfkBudvpe/tXaOXkzy5nVFXs4921/jAaMTwzcJIt0bTXZpp5cExdlL7w9ZrnehARHiposQ==", "dev": true, "license": "MIT", "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.6.0", - "@typespec/http": "^1.6.0" + "@typespec/compiler": "^1.7.0", + "@typespec/http": "^1.7.0" } }, "node_modules/@typespec/rest": { - "version": "0.76.0", - "resolved": "https://registry.npmjs.org/@typespec/rest/-/rest-0.76.0.tgz", - "integrity": "sha512-6jtQWdcmuKyG9cmqWsJjaq64f6N5B/1DS4X3ZoTNgYhHA27Hnsxo1HZWXcpv7Wl+MxLAZM6kgpML0ugDEZcrYQ==", + "version": "0.77.0", + "resolved": "https://registry.npmjs.org/@typespec/rest/-/rest-0.77.0.tgz", + "integrity": "sha512-DEUMD9zYqUVUhKCGktV7Z+sFkzj+bcSpJRhEXxOrJxupWM4I3N4deMop+ulxezxlLxIRUz7ELc+6WucYXgOnAA==", "dev": true, "license": "MIT", "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.6.0", - "@typespec/http": "^1.6.0" + "@typespec/compiler": "^1.7.0", + "@typespec/http": "^1.7.0" } }, "node_modules/@typespec/spec-api": { - "version": "0.1.0-alpha.10", - "resolved": "https://registry.npmjs.org/@typespec/spec-api/-/spec-api-0.1.0-alpha.10.tgz", - "integrity": "sha512-LvwlhMnwqzCjmwOPuoE1jPfK+474qmo29Jq4Da2FZkjZbDsbyWuU4FRptRMhjsNj3ITMz/VulShXq4eXz4VroQ==", + "version": "0.1.0-alpha.11", + "resolved": "https://registry.npmjs.org/@typespec/spec-api/-/spec-api-0.1.0-alpha.11.tgz", + "integrity": "sha512-qNQ8Oc7ha9MzRMfcF4djRaxa7gmM9CUetNeZIVJO4PZDIe9Rb/HMX9C3LP0f5LiiYkE8KvA/jLAR4FSYqp0onA==", "dev": true, "license": "MIT", "dependencies": { @@ -2460,57 +2539,46 @@ } }, "node_modules/@typespec/spec-coverage-sdk": { - "version": "0.1.0-alpha.12", - "resolved": "https://registry.npmjs.org/@typespec/spec-coverage-sdk/-/spec-coverage-sdk-0.1.0-alpha.12.tgz", - "integrity": "sha512-eqzNQ+bZn25SP8GZyf6qgCwXL1U5/OF5AvKFl7AlYfSSuB0ybeWaDQ14jZzl5gnFXY8lCc8P0ycK1HjtwdGyqw==", + "version": "0.1.0-alpha.13", + "resolved": "https://registry.npmjs.org/@typespec/spec-coverage-sdk/-/spec-coverage-sdk-0.1.0-alpha.13.tgz", + "integrity": "sha512-GpCWrbcMQis+utHukdWdY85lNeQX89OBYiBovOxCGO5DmUmqnPQWzHZIggoAQ6fuSlC+tZoWAbY5hygN1QzPPA==", "dev": true, "license": "MIT", "dependencies": { "@azure/identity": "~4.13.0", "@azure/storage-blob": "~12.29.1", - "@types/node": "~24.9.1" + "@types/node": "~24.10.1" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@typespec/spec-coverage-sdk/node_modules/@types/node": { - "version": "24.9.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.9.2.tgz", - "integrity": "sha512-uWN8YqxXxqFMX2RqGOrumsKeti4LlmIMIyV0lgut4jx7KQBcBiW6vkDtIBvHnHIquwNfJhk8v2OtmO8zXWHfPA==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~7.16.0" - } - }, "node_modules/@typespec/spector": { - "version": "0.1.0-alpha.20", - "resolved": "https://registry.npmjs.org/@typespec/spector/-/spector-0.1.0-alpha.20.tgz", - "integrity": "sha512-qnR3NizzYu8e7TNcXY+CFp/FkXk8DJCtk3lpWPC3bNaNjxtuUjZ6Miix0gCPjDBCGOv8iquT7mLux103kMKLWQ==", + "version": "0.1.0-alpha.21", + "resolved": "https://registry.npmjs.org/@typespec/spector/-/spector-0.1.0-alpha.21.tgz", + "integrity": "sha512-oLtAs2/E+ee/OPeMZnRUxiuVjUeYaxi5R1KeFThAjLszp6M2rkCfeIdyj2RosGxiqWrmoEd9oCWO/fHwvGVZew==", "dev": true, "license": "MIT", "dependencies": { "@azure/identity": "~4.13.0", - "@types/js-yaml": "^4.0.5", - "@typespec/compiler": "^1.6.0", - "@typespec/http": "^1.6.0", - "@typespec/rest": "^0.76.0", - "@typespec/spec-api": "^0.1.0-alpha.10", - "@typespec/spec-coverage-sdk": "^0.1.0-alpha.12", - "@typespec/versioning": "^0.76.0", + "@typespec/compiler": "^1.7.0", + "@typespec/http": "^1.7.0", + "@typespec/rest": "^0.77.0", + "@typespec/spec-api": "^0.1.0-alpha.11", + "@typespec/spec-coverage-sdk": "^0.1.0-alpha.13", + "@typespec/versioning": "^0.77.0", "ajv": "~8.17.1", "body-parser": "^2.2.0", "deep-equal": "^2.2.0", "express": "^5.1.0", - "globby": "~15.0.0", - "js-yaml": "^4.1.0", + "globby": "~16.0.0", "micromatch": "^4.0.8", "morgan": "^1.10.0", "multer": "^2.0.1", "picocolors": "~1.1.1", "source-map-support": "~0.5.21", "xml2js": "^0.6.2", + "yaml": "~2.8.0", "yargs": "~18.0.0" }, "bin": { @@ -2666,32 +2734,32 @@ } }, "node_modules/@typespec/sse": { - "version": "0.76.0", - "resolved": "https://registry.npmjs.org/@typespec/sse/-/sse-0.76.0.tgz", - "integrity": "sha512-mCd4oAXr0Tt990T2PDjx+6H0jmPHINyCH0XRU2HrWtGW5lG/NQVIs5oOxElc7NGg629HrolfLTw0oW8hdMD7Eg==", + "version": "0.77.0", + "resolved": "https://registry.npmjs.org/@typespec/sse/-/sse-0.77.0.tgz", + "integrity": "sha512-rVML/sPNj+MomKXftko/eUNM5OhHlIevoit3Dbtaf1aWS5pcJ5jKX05Prz53VIyeUP7ra5ocmPE/iIEPb8ZbCA==", "dev": true, "license": "MIT", "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.6.0", - "@typespec/events": "^0.76.0", - "@typespec/http": "^1.6.0", - "@typespec/streams": "^0.76.0" + "@typespec/compiler": "^1.7.0", + "@typespec/events": "^0.77.0", + "@typespec/http": "^1.7.0", + "@typespec/streams": "^0.77.0" } }, "node_modules/@typespec/streams": { - "version": "0.76.0", - "resolved": "https://registry.npmjs.org/@typespec/streams/-/streams-0.76.0.tgz", - "integrity": "sha512-7gQPtsokyn0Mjr43MAik6ZkQt1PZjseU+KcBE2iGT9P6oWYYTH3K1C4LLGXHZAbgEtBvFn4S+U8HPbDhj4nEhw==", + "version": "0.77.0", + "resolved": "https://registry.npmjs.org/@typespec/streams/-/streams-0.77.0.tgz", + "integrity": "sha512-qqfJW4n19Jgi5FxQhsEgoIc5zD9o47AAoZxLKUX91z6aB/YWrLSTrrrIAvhNCESXuB89zlJPwlZ/j4YmpxZ/jw==", "dev": true, "license": "MIT", "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.6.0" + "@typespec/compiler": "^1.7.0" } }, "node_modules/@typespec/ts-http-runtime": { @@ -2710,29 +2778,29 @@ } }, "node_modules/@typespec/versioning": { - "version": "0.76.0", - "resolved": "https://registry.npmjs.org/@typespec/versioning/-/versioning-0.76.0.tgz", - "integrity": "sha512-dguO/B+mwlCyenWGG+M+16cMQuGHSTJbU5Z0pyUou1uyWrB1px//s4pW7PKD14S+fPutJE0wTMQm+CctOq6quA==", + "version": "0.77.0", + "resolved": "https://registry.npmjs.org/@typespec/versioning/-/versioning-0.77.0.tgz", + "integrity": "sha512-eAInPZYPkxpBUS8IKQfNZ5eZsLfkWqEX0d6YM/AfooGYbxcKdHQBfYOWBvRC4NkKEMub4ROaD5GcPLYTyWQIWw==", "dev": true, "license": "MIT", "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.6.0" + "@typespec/compiler": "^1.7.0" } }, "node_modules/@typespec/xml": { - "version": "0.76.0", - "resolved": "https://registry.npmjs.org/@typespec/xml/-/xml-0.76.0.tgz", - "integrity": "sha512-+I7hdWZDO3qBfzRT3St+1Dg/NQAMNLz8w1OydutSnVMx0G3KWg/ESonaByszBUfdq6Z5iTtls3gvj4wgrw80gA==", + "version": "0.77.0", + "resolved": "https://registry.npmjs.org/@typespec/xml/-/xml-0.77.0.tgz", + "integrity": "sha512-DNVAOMaRUPGpLEsqf3sn7UAWuAE1rs8Jf1FIAU7DF/sVmzeXs4OBanxSSsVmbcdfPRHPbjPuRnW6e+QS2Sjk3Q==", "dev": true, "license": "MIT", "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.6.0" + "@typespec/compiler": "^1.7.0" } }, "node_modules/@vitest/coverage-v8": { @@ -2974,22 +3042,6 @@ } } }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -3160,23 +3212,6 @@ "url": "https://opencollective.com/express" } }, - "node_modules/body-parser/node_modules/iconv-lite": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", - "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, "node_modules/brace-expansion": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", @@ -3353,9 +3388,9 @@ "dev": true }, "node_modules/chardet": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.0.tgz", - "integrity": "sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.1.tgz", + "integrity": "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==", "dev": true, "license": "MIT" }, @@ -3410,16 +3445,17 @@ } }, "node_modules/content-disposition": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", - "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", + "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", "dev": true, "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/content-type": { @@ -3524,9 +3560,9 @@ } }, "node_modules/default-browser": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.3.0.tgz", - "integrity": "sha512-Qq68+VkJlc8tjnPV1i7HtbIn7ohmjZa88qUvHMIK0ZKUXMCuV45cT7cEXALPUmeXCe0q1DWQkQTemHVaLIFSrg==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.4.0.tgz", + "integrity": "sha512-XDuvSq38Hr1MdN47EDvYtx3U0MTqpCEn+F6ft8z2vYDzMrvQhVp0ui9oQdqW3MvK3vqUETglt1tVGgjLuJ5izg==", "dev": true, "license": "MIT", "dependencies": { @@ -3541,9 +3577,9 @@ } }, "node_modules/default-browser-id": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", - "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", "dev": true, "license": "MIT", "engines": { @@ -3849,19 +3885,20 @@ } }, "node_modules/express": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", - "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "dev": true, "license": "MIT", "dependencies": { "accepts": "^2.0.0", - "body-parser": "^2.2.0", + "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", + "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", @@ -3921,9 +3958,9 @@ "dev": true }, "node_modules/fast-xml-parser": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.3.1.tgz", - "integrity": "sha512-jbNkWiv2Ec1A7wuuxk0br0d0aTMUtQ4IkL+l/i1r9PRf6pLXjDgsBsWwO+UyczmQlnehi4Tbc8/KIvxGQe+I/A==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.3.2.tgz", + "integrity": "sha512-n8v8b6p4Z1sMgqRmqLJm3awW4NX7NkaKPfb3uJIBTSH7Pdvufi3PQ3/lJLQrvxcMYl7JI2jnDO90siPEpD8JBA==", "dev": true, "funding": [ { @@ -3970,9 +4007,9 @@ } }, "node_modules/finalhandler": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", - "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", "dev": true, "license": "MIT", "dependencies": { @@ -3984,7 +4021,11 @@ "statuses": "^2.0.1" }, "engines": { - "node": ">= 0.8" + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/find-up": { @@ -4221,18 +4262,18 @@ } }, "node_modules/globby": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-15.0.0.tgz", - "integrity": "sha512-oB4vkQGqlMl682wL1IlWd02tXCbquGWM4voPEI85QmNKCaw8zGTm1f1rubFgkg3Eli2PtKlFgrnmUqasbQWlkw==", + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-16.0.0.tgz", + "integrity": "sha512-ejy4TJFga99yW6Q0uhM3pFawKWZmtZzZD/v/GwI5+9bCV5Ew+D2pSND6W7fUes5UykqSsJkUfxFVdRh7Q1+P3Q==", "dev": true, "license": "MIT", "dependencies": { "@sindresorhus/merge-streams": "^4.0.0", "fast-glob": "^3.3.3", "ignore": "^7.0.5", - "path-type": "^6.0.0", + "is-path-inside": "^4.0.0", "slash": "^5.1.0", - "unicorn-magic": "^0.3.0" + "unicorn-magic": "^0.4.0" }, "engines": { "node": ">=20" @@ -4343,30 +4384,24 @@ "dev": true }, "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "dev": true, "license": "MIT", "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" }, "engines": { "node": ">= 0.8" - } - }, - "node_modules/http-errors/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/http-proxy-agent": { @@ -4398,9 +4433,9 @@ } }, "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", + "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4408,6 +4443,10 @@ }, "engines": { "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/ignore": { @@ -4683,6 +4722,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-path-inside": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz", + "integrity": "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-promise": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", @@ -4954,13 +5006,13 @@ } }, "node_modules/jsonwebtoken": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", - "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", + "integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==", "dev": true, "license": "MIT", "dependencies": { - "jws": "^3.2.2", + "jws": "^4.0.1", "lodash.includes": "^4.3.0", "lodash.isboolean": "^3.0.3", "lodash.isinteger": "^4.0.4", @@ -4977,9 +5029,9 @@ } }, "node_modules/jwa": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz", - "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", "dev": true, "license": "MIT", "dependencies": { @@ -4989,13 +5041,13 @@ } }, "node_modules/jws": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.3.tgz", - "integrity": "sha512-byiJ0FLRdLdSVSReO/U4E7RoEyOCKnEnEPMjq3HxWtvzLsV08/i5RQKsFVNkCldrCaPr2vDNAOMsfs8T/Hze7g==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", "dev": true, "license": "MIT", "dependencies": { - "jwa": "^1.4.2", + "jwa": "^2.0.1", "safe-buffer": "^5.0.1" } }, @@ -5183,16 +5235,20 @@ } }, "node_modules/mime-types": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", - "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "dev": true, "license": "MIT", "dependencies": { "mime-db": "^1.54.0" }, "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/minimatch": { @@ -5395,13 +5451,13 @@ } }, "node_modules/mute-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", - "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-3.0.0.tgz", + "integrity": "sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==", "dev": true, "license": "ISC", "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/nanoid": { @@ -5667,19 +5723,6 @@ "url": "https://opencollective.com/express" } }, - "node_modules/path-type": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz", - "integrity": "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/pathe": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", @@ -5856,38 +5899,21 @@ } }, "node_modules/raw-body": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.1.tgz", - "integrity": "sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", "dev": true, "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.7.0", - "unpipe": "1.0.0" + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.10" } }, - "node_modules/raw-body/node_modules/iconv-lite": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", - "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -6844,19 +6870,6 @@ "dev": true, "license": "0BSD" }, - "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/type-is": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", @@ -6901,13 +6914,13 @@ "license": "MIT" }, "node_modules/unicorn-magic": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", - "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.4.0.tgz", + "integrity": "sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==", "dev": true, "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -7475,19 +7488,6 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } - }, - "node_modules/yoctocolors-cjs": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz", - "integrity": "sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } } } } diff --git a/packages/http-client-java/package.json b/packages/http-client-java/package.json index 63f510b4c5a..061c137213c 100644 --- a/packages/http-client-java/package.json +++ b/packages/http-client-java/package.json @@ -1,6 +1,6 @@ { "name": "@typespec/http-client-java", - "version": "0.6.0", + "version": "0.6.1", "description": "TypeSpec library for emitting Java client from the TypeSpec REST protocol binding", "keywords": [ "TypeSpec" @@ -49,19 +49,19 @@ "generator/http-client-generator/target/classes/PerfAutomation.jfc" ], "peerDependencies": { - "@azure-tools/typespec-autorest": ">=0.62.0 <1.0.0", - "@azure-tools/typespec-azure-core": ">=0.62.0 <1.0.0", - "@azure-tools/typespec-azure-resource-manager": ">=0.62.1 <1.0.0", - "@azure-tools/typespec-client-generator-core": ">=0.62.0 <1.0.0", - "@typespec/compiler": "^1.6.0", - "@typespec/events": ">=0.76.0 <1.0.0", - "@typespec/http": "^1.6.0", - "@typespec/openapi": "^1.6.0", - "@typespec/rest": ">=0.76.0 <1.0.0", - "@typespec/sse": ">=0.76.0 <1.0.0", - "@typespec/streams": ">=0.76.0 <1.0.0", - "@typespec/versioning": ">=0.76.0 <1.0.0", - "@typespec/xml": ">=0.76.0 <1.0.0" + "@azure-tools/typespec-autorest": ">=0.63.0 <1.0.0", + "@azure-tools/typespec-azure-core": ">=0.63.0 <1.0.0", + "@azure-tools/typespec-azure-resource-manager": ">=0.63.0 <1.0.0", + "@azure-tools/typespec-client-generator-core": ">=0.63.0 <1.0.0", + "@typespec/compiler": "^1.7.0", + "@typespec/events": ">=0.77.0 <1.0.0", + "@typespec/http": "^1.7.0", + "@typespec/openapi": "^1.7.0", + "@typespec/rest": ">=0.77.0 <1.0.0", + "@typespec/sse": ">=0.77.0 <1.0.0", + "@typespec/streams": ">=0.77.0 <1.0.0", + "@typespec/versioning": ">=0.77.0 <1.0.0", + "@typespec/xml": ">=0.77.0 <1.0.0" }, "dependencies": { "@autorest/codemodel": "~4.20.1", @@ -69,26 +69,26 @@ "lodash": "~4.17.21" }, "devDependencies": { - "@azure-tools/typespec-autorest": "0.62.0", - "@azure-tools/typespec-azure-core": "0.62.0", - "@azure-tools/typespec-azure-resource-manager": "0.62.1", - "@azure-tools/typespec-azure-rulesets": "0.62.0", - "@azure-tools/typespec-client-generator-core": "0.62.0", + "@azure-tools/typespec-autorest": "0.63.0", + "@azure-tools/typespec-azure-core": "0.63.0", + "@azure-tools/typespec-azure-resource-manager": "0.63.0", + "@azure-tools/typespec-azure-rulesets": "0.63.0", + "@azure-tools/typespec-client-generator-core": "0.63.0", "@microsoft/api-extractor": "^7.55.1", "@microsoft/api-extractor-model": "^7.32.1", "@types/js-yaml": "~4.0.9", "@types/lodash": "~4.17.21", "@types/node": "~24.10.1", - "@typespec/compiler": "1.6.0", - "@typespec/events": "0.76.0", - "@typespec/http": "1.6.0", - "@typespec/openapi": "1.6.0", - "@typespec/rest": "0.76.0", - "@typespec/spector": "0.1.0-alpha.20", - "@typespec/sse": "0.76.0", - "@typespec/streams": "0.76.0", - "@typespec/versioning": "0.76.0", - "@typespec/xml": "0.76.0", + "@typespec/compiler": "1.7.0", + "@typespec/events": "0.77.0", + "@typespec/http": "1.7.0", + "@typespec/openapi": "1.7.0", + "@typespec/rest": "0.77.0", + "@typespec/spector": "0.1.0-alpha.21", + "@typespec/sse": "0.77.0", + "@typespec/streams": "0.77.0", + "@typespec/versioning": "0.77.0", + "@typespec/xml": "0.77.0", "@vitest/coverage-v8": "^4.0.14", "@vitest/ui": "^4.0.14", "c8": "~10.1.3", From 08179f67211f89f4ffbda5462baa520cadc02d07 Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Sat, 13 Dec 2025 00:01:35 +0800 Subject: [PATCH 32/40] [Python] Support encode for array of string in serialization and deserialization (#9146) fix https://github.com/microsoft/typespec/issues/9026 TCGC is ready: https://github.com/Azure/typespec-azure/pull/3583 Spector case: https://github.com/microsoft/typespec/pull/9106 --- .../python-array-encode-2025-11-5-10-12-9.md | 7 + .../http-client-python/emitter/src/types.ts | 1 + .../pygen/codegen/models/property.py | 1 + .../codegen/serializers/model_serializer.py | 2 + .../codegen/templates/model_base.py.jinja2 | 28 ++ .../asynctests/test_encode_array_async.py | 43 +++ .../test_encode_array.py | 38 +++ .../test_model_base_serialization.py | 264 ++++++++++++++++++ 8 files changed, 384 insertions(+) create mode 100644 .chronus/changes/python-array-encode-2025-11-5-10-12-9.md create mode 100644 packages/http-client-python/generator/test/generic_mock_api_tests/asynctests/test_encode_array_async.py create mode 100644 packages/http-client-python/generator/test/generic_mock_api_tests/test_encode_array.py diff --git a/.chronus/changes/python-array-encode-2025-11-5-10-12-9.md b/.chronus/changes/python-array-encode-2025-11-5-10-12-9.md new file mode 100644 index 00000000000..af788a49a8f --- /dev/null +++ b/.chronus/changes/python-array-encode-2025-11-5-10-12-9.md @@ -0,0 +1,7 @@ +--- +changeKind: feature +packages: + - "@typespec/http-client-python" +--- + +Support encode for array of string in serialization and deserialization \ No newline at end of file diff --git a/packages/http-client-python/emitter/src/types.ts b/packages/http-client-python/emitter/src/types.ts index ffa8fc418df..59fcdb2367d 100644 --- a/packages/http-client-python/emitter/src/types.ts +++ b/packages/http-client-python/emitter/src/types.ts @@ -249,6 +249,7 @@ function emitProperty( flatten: property.flatten, isMultipartFileInput: isMultipartFileInput, xmlMetadata: getXmlMetadata(property), + encode: property.encode, }; } diff --git a/packages/http-client-python/generator/pygen/codegen/models/property.py b/packages/http-client-python/generator/pygen/codegen/models/property.py index dbdf01aa7d0..ca18aba8ddf 100644 --- a/packages/http-client-python/generator/pygen/codegen/models/property.py +++ b/packages/http-client-python/generator/pygen/codegen/models/property.py @@ -40,6 +40,7 @@ def __init__( self.is_multipart_file_input: bool = yaml_data.get("isMultipartFileInput", False) self.flatten = self.yaml_data.get("flatten", False) and not getattr(self.type, "flattened_property", False) self.original_tsp_name: Optional[str] = self.yaml_data.get("originalTspName") + self.encode: Optional[str] = self.yaml_data.get("encode") def pylint_disable(self) -> str: retval: str = "" diff --git a/packages/http-client-python/generator/pygen/codegen/serializers/model_serializer.py b/packages/http-client-python/generator/pygen/codegen/serializers/model_serializer.py index b533c65f3e8..cf17f26e1fd 100644 --- a/packages/http-client-python/generator/pygen/codegen/serializers/model_serializer.py +++ b/packages/http-client-python/generator/pygen/codegen/serializers/model_serializer.py @@ -329,6 +329,8 @@ def declare_property(self, prop: Property) -> str: args.append("is_multipart_file_input=True") elif hasattr(prop.type, "encode") and prop.type.encode: # type: ignore args.append(f'format="{prop.type.encode}"') # type: ignore + elif prop.encode: + args.append(f'format="{prop.encode}"') if prop.xml_metadata: args.append(f"xml={prop.xml_metadata}") diff --git a/packages/http-client-python/generator/pygen/codegen/templates/model_base.py.jinja2 b/packages/http-client-python/generator/pygen/codegen/templates/model_base.py.jinja2 index e374e0e4887..4211882d35d 100644 --- a/packages/http-client-python/generator/pygen/codegen/templates/model_base.py.jinja2 +++ b/packages/http-client-python/generator/pygen/codegen/templates/model_base.py.jinja2 @@ -179,6 +179,19 @@ _VALID_RFC7231 = re.compile( r"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s\d{4}\s\d{2}:\d{2}:\d{2}\sGMT" ) +_ARRAY_ENCODE_MAPPING = { + "pipeDelimited": "|", + "spaceDelimited": " ", + "commaDelimited": ",", + "newlineDelimited": "\n", +} + +def _deserialize_array_encoded(delimit: str, attr): + if isinstance(attr, str): + if attr == "": + return [] + return attr.split(delimit) + return attr def _deserialize_datetime(attr: typing.Union[str, datetime]) -> datetime: """Deserialize ISO-8601 formatted string into Datetime object. @@ -323,6 +336,8 @@ _DESERIALIZE_MAPPING_WITHFORMAT = { def get_deserializer(annotation: typing.Any, rf: typing.Optional["_RestField"] = None): if annotation is int and rf and rf._format == "str": return _deserialize_int_as_str + if annotation is str and rf and rf._format in _ARRAY_ENCODE_MAPPING: + return functools.partial(_deserialize_array_encoded, _ARRAY_ENCODE_MAPPING[rf._format]) if rf and rf._format: return _DESERIALIZE_MAPPING_WITHFORMAT.get(rf._format) {% if code_model.has_external_type %} @@ -497,6 +512,8 @@ def _is_model(obj: typing.Any) -> bool: def _serialize(o, format: typing.Optional[str] = None): # pylint: disable=too-many-return-statements if isinstance(o, list): + if format in _ARRAY_ENCODE_MAPPING and all(isinstance(x, str) for x in o): + return _ARRAY_ENCODE_MAPPING[format].join(o) return [_serialize(x, format) for x in o] if isinstance(o, dict): return {k: _serialize(v, format) for k, v in o.items()} @@ -809,6 +826,17 @@ def _deserialize_sequence( return obj if isinstance(obj, ET.Element): obj = list(obj) + try: + if ( + isinstance(obj, str) + and isinstance(deserializer, functools.partial) + and isinstance(deserializer.args[0], functools.partial) + and deserializer.args[0].func == _deserialize_array_encoded # pylint: disable=comparison-with-callable + ): + # encoded string may be deserialized to sequence + return deserializer(obj) + except: # pylint: disable=bare-except + pass return type(obj)(_deserialize(deserializer, entry, module) for entry in obj) diff --git a/packages/http-client-python/generator/test/generic_mock_api_tests/asynctests/test_encode_array_async.py b/packages/http-client-python/generator/test/generic_mock_api_tests/asynctests/test_encode_array_async.py new file mode 100644 index 00000000000..27cae3caa09 --- /dev/null +++ b/packages/http-client-python/generator/test/generic_mock_api_tests/asynctests/test_encode_array_async.py @@ -0,0 +1,43 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +import pytest +from encode.array.aio import ArrayClient +from encode.array import models + + +@pytest.fixture +async def client(): + async with ArrayClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_comma_delimited(client: ArrayClient): + body = models.CommaDelimitedArrayProperty(value=["blue", "red", "green"]) + result = await client.property.comma_delimited(body) + assert result.value == ["blue", "red", "green"] + + +@pytest.mark.asyncio +async def test_space_delimited(client: ArrayClient): + body = models.SpaceDelimitedArrayProperty(value=["blue", "red", "green"]) + result = await client.property.space_delimited(body) + assert result.value == ["blue", "red", "green"] + + +@pytest.mark.asyncio +async def test_pipe_delimited(client: ArrayClient): + body = models.PipeDelimitedArrayProperty(value=["blue", "red", "green"]) + result = await client.property.pipe_delimited(body) + assert result.value == ["blue", "red", "green"] + + +@pytest.mark.asyncio +async def test_newline_delimited(client: ArrayClient): + body = models.NewlineDelimitedArrayProperty(value=["blue", "red", "green"]) + result = await client.property.newline_delimited(body) + assert result.value == ["blue", "red", "green"] diff --git a/packages/http-client-python/generator/test/generic_mock_api_tests/test_encode_array.py b/packages/http-client-python/generator/test/generic_mock_api_tests/test_encode_array.py new file mode 100644 index 00000000000..3e1b48c908e --- /dev/null +++ b/packages/http-client-python/generator/test/generic_mock_api_tests/test_encode_array.py @@ -0,0 +1,38 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +import pytest +from encode.array import ArrayClient, models + + +@pytest.fixture +def client(): + with ArrayClient() as client: + yield client + + +def test_comma_delimited(client: ArrayClient): + body = models.CommaDelimitedArrayProperty(value=["blue", "red", "green"]) + result = client.property.comma_delimited(body) + assert result.value == ["blue", "red", "green"] + + +def test_space_delimited(client: ArrayClient): + body = models.SpaceDelimitedArrayProperty(value=["blue", "red", "green"]) + result = client.property.space_delimited(body) + assert result.value == ["blue", "red", "green"] + + +def test_pipe_delimited(client: ArrayClient): + body = models.PipeDelimitedArrayProperty(value=["blue", "red", "green"]) + result = client.property.pipe_delimited(body) + assert result.value == ["blue", "red", "green"] + + +def test_newline_delimited(client: ArrayClient): + body = models.NewlineDelimitedArrayProperty(value=["blue", "red", "green"]) + result = client.property.newline_delimited(body) + assert result.value == ["blue", "red", "green"] diff --git a/packages/http-client-python/generator/test/unittests/test_model_base_serialization.py b/packages/http-client-python/generator/test/unittests/test_model_base_serialization.py index f971e59836f..4f45174a7aa 100644 --- a/packages/http-client-python/generator/test/unittests/test_model_base_serialization.py +++ b/packages/http-client-python/generator/test/unittests/test_model_base_serialization.py @@ -4108,3 +4108,267 @@ def test_multi_layer_discriminator(): assert AnotherPet(name="Buddy", trained=True) == model_pet assert AnotherDog(name="Rex", trained=True, breed="German Shepherd") == model_dog + + +def test_array_encode_comma_delimited(): + """Test commaDelimited format for array of strings""" + + class CommaDelimitedModel(Model): + colors: list[str] = rest_field(format="commaDelimited") + + @overload + def __init__(self, *, colors: list[str]): ... + + @overload + def __init__(self, mapping: Mapping[str, Any], /): ... + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + # Test serialization: list[str] -> comma-delimited string + model = CommaDelimitedModel(colors=["blue", "red", "green"]) + assert model.colors == ["blue", "red", "green"] + assert model["colors"] == "blue,red,green" + + # Test deserialization: comma-delimited string -> list[str] + model = CommaDelimitedModel({"colors": "blue,red,green"}) + assert model.colors == ["blue", "red", "green"] + assert model["colors"] == "blue,red,green" + + # Test with empty list + model = CommaDelimitedModel(colors=[]) + assert model.colors == [] + assert model["colors"] == "" + + # Test with single item + model = CommaDelimitedModel(colors=["blue"]) + assert model.colors == ["blue"] + assert model["colors"] == "blue" + + +def test_array_encode_pipe_delimited(): + """Test pipeDelimited format for array of strings""" + + class PipeDelimitedModel(Model): + colors: list[str] = rest_field(format="pipeDelimited") + + @overload + def __init__(self, *, colors: list[str]): ... + + @overload + def __init__(self, mapping: Mapping[str, Any], /): ... + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + # Test serialization: list[str] -> pipe-delimited string + model = PipeDelimitedModel(colors=["blue", "red", "green"]) + assert model.colors == ["blue", "red", "green"] + assert model["colors"] == "blue|red|green" + + # Test deserialization: pipe-delimited string -> list[str] + model = PipeDelimitedModel({"colors": "blue|red|green"}) + assert model.colors == ["blue", "red", "green"] + assert model["colors"] == "blue|red|green" + + # Test with empty list + model = PipeDelimitedModel(colors=[]) + assert model.colors == [] + assert model["colors"] == "" + + +def test_array_encode_space_delimited(): + """Test spaceDelimited format for array of strings""" + + class SpaceDelimitedModel(Model): + colors: list[str] = rest_field(format="spaceDelimited") + + @overload + def __init__(self, *, colors: list[str]): ... + + @overload + def __init__(self, mapping: Mapping[str, Any], /): ... + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + # Test serialization: list[str] -> space-delimited string + model = SpaceDelimitedModel(colors=["blue", "red", "green"]) + assert model.colors == ["blue", "red", "green"] + assert model["colors"] == "blue red green" + + # Test deserialization: space-delimited string -> list[str] + model = SpaceDelimitedModel({"colors": "blue red green"}) + assert model.colors == ["blue", "red", "green"] + assert model["colors"] == "blue red green" + + # Test with empty list + model = SpaceDelimitedModel(colors=[]) + assert model.colors == [] + assert model["colors"] == "" + + +def test_array_encode_newline_delimited(): + """Test newlineDelimited format for array of strings""" + + class NewlineDelimitedModel(Model): + colors: list[str] = rest_field(format="newlineDelimited") + + @overload + def __init__(self, *, colors: list[str]): ... + + @overload + def __init__(self, mapping: Mapping[str, Any], /): ... + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + # Test serialization: list[str] -> newline-delimited string + model = NewlineDelimitedModel(colors=["blue", "red", "green"]) + assert model.colors == ["blue", "red", "green"] + assert model["colors"] == "blue\nred\ngreen" + + # Test deserialization: newline-delimited string -> list[str] + model = NewlineDelimitedModel({"colors": "blue\nred\ngreen"}) + assert model.colors == ["blue", "red", "green"] + assert model["colors"] == "blue\nred\ngreen" + + # Test with empty list + model = NewlineDelimitedModel(colors=[]) + assert model.colors == [] + assert model["colors"] == "" + + +def test_array_encode_optional(): + """Test array encoding with optional fields""" + + class OptionalEncodedModel(Model): + colors: Optional[list[str]] = rest_field(default=None, format="commaDelimited") + + @overload + def __init__(self, *, colors: Optional[list[str]] = None): ... + + @overload + def __init__(self, mapping: Mapping[str, Any], /): ... + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + # Test with None + model = OptionalEncodedModel(colors=None) + assert model.colors is None + assert model["colors"] is None + + # Test with value + model = OptionalEncodedModel(colors=["blue", "red"]) + assert model.colors == ["blue", "red"] + assert model["colors"] == "blue,red" + + # Test deserialization with None + model = OptionalEncodedModel({"colors": None}) + assert model.colors is None + + +def test_array_encode_modification(): + """Test modifying array-encoded fields""" + + class ModifiableModel(Model): + colors: list[str] = rest_field(format="commaDelimited") + + @overload + def __init__(self, *, colors: list[str]): ... + + @overload + def __init__(self, mapping: Mapping[str, Any], /): ... + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + model = ModifiableModel(colors=["blue", "red"]) + assert model.colors == ["blue", "red"] + assert model["colors"] == "blue,red" + + # Modify through property + model.colors = ["green", "yellow", "purple"] + assert model.colors == ["green", "yellow", "purple"] + assert model["colors"] == "green,yellow,purple" + + # Modify through dict access + model["colors"] = "orange,pink" + assert model.colors == ["orange", "pink"] + assert model["colors"] == "orange,pink" + + +def test_array_encode_json_roundtrip(): + """Test JSON serialization and deserialization with array encoding""" + + class JsonModel(Model): + pipe_colors: list[str] = rest_field(name="pipeColors", format="pipeDelimited") + comma_colors: list[str] = rest_field(name="commaColors", format="commaDelimited") + + @overload + def __init__( + self, + *, + pipe_colors: list[str], + comma_colors: list[str], + ): ... + + @overload + def __init__(self, mapping: Mapping[str, Any], /): ... + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + model = JsonModel( + pipe_colors=["blue", "red", "green"], + comma_colors=["small", "medium", "large"], + ) + + # Serialize to JSON + json_str = json.dumps(dict(model), cls=SdkJSONEncoder) + assert json.loads(json_str) == { + "pipeColors": "blue|red|green", + "commaColors": "small,medium,large", + } + + # Deserialize from JSON + deserialized = JsonModel(json.loads(json_str)) + assert deserialized.pipe_colors == ["blue", "red", "green"] + assert deserialized.comma_colors == ["small", "medium", "large"] + + +def test_array_encode_with_special_characters(): + """Test array encoding with strings containing special characters""" + + class SpecialCharsModel(Model): + comma_values: list[str] = rest_field(name="commaValues", format="commaDelimited") + pipe_values: list[str] = rest_field(name="pipeValues", format="pipeDelimited") + + @overload + def __init__( + self, + *, + comma_values: list[str], + pipe_values: list[str], + ): ... + + @overload + def __init__(self, mapping: Mapping[str, Any], /): ... + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + # Test with strings that might contain delimiters + # Note: In real usage, the strings should not contain the delimiter character + # This test documents current behavior + model = SpecialCharsModel( + comma_values=["value with spaces", "another-value", "value_3"], + pipe_values=["path/to/file", "another-path", "final.path"], + ) + + assert model.comma_values == ["value with spaces", "another-value", "value_3"] + assert model["commaValues"] == "value with spaces,another-value,value_3" + + assert model.pipe_values == ["path/to/file", "another-path", "final.path"] + assert model["pipeValues"] == "path/to/file|another-path|final.path" From 85a59e53b12326f36bc34e554707e47ec41f95ae Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Fri, 12 Dec 2025 14:53:48 -0500 Subject: [PATCH 33/40] Fix problem pane (#9174) fix #8560(keyboard not working) fix #8559(role) --- .chronus/changes/fix-problem-pane-2025-11-10-14-5-0.md | 8 ++++++++ packages/playground/src/react/problem-pane/header.tsx | 2 ++ 2 files changed, 10 insertions(+) create mode 100644 .chronus/changes/fix-problem-pane-2025-11-10-14-5-0.md diff --git a/.chronus/changes/fix-problem-pane-2025-11-10-14-5-0.md b/.chronus/changes/fix-problem-pane-2025-11-10-14-5-0.md new file mode 100644 index 00000000000..ed464204af5 --- /dev/null +++ b/.chronus/changes/fix-problem-pane-2025-11-10-14-5-0.md @@ -0,0 +1,8 @@ +--- +# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking +changeKind: fix +packages: + - "@typespec/playground" +--- + +[a11y] Fix problem pane not usable via keyboard diff --git a/packages/playground/src/react/problem-pane/header.tsx b/packages/playground/src/react/problem-pane/header.tsx index 0ff3587093a..ecddc475888 100644 --- a/packages/playground/src/react/problem-pane/header.tsx +++ b/packages/playground/src/react/problem-pane/header.tsx @@ -59,6 +59,7 @@ interface ContainerProps { const Container = ({ children, className, status, onClick, collaped }: ContainerProps) => { return (
(evt.code === "Enter" || evt.code === "Space") && onClick?.(evt as any)} >
{children}
Date: Fri, 12 Dec 2025 15:18:13 -0600 Subject: [PATCH 34/40] Refactor enum creation (#9197) This PR refactors the enum creation to allow visitors to mutate an enum's namespace and the generator to load any custom code in the new namespace for said visitor, before the final enum type is added to the output library. fixes: https://github.com/Azure/azure-sdk-for-net/issues/54368 --- .../src/Providers/EnumProvider.cs | 22 +--- .../src/Providers/ExtensibleEnumProvider.cs | 1 + .../src/Providers/FixedEnumProvider.cs | 1 + .../src/Providers/TypeProvider.cs | 7 +- .../src/TypeFactory.cs | 28 +++++ .../src/Utilities/DiagnosticCodes.cs | 1 + .../test/InputLibraryVisitorTests.cs | 3 +- .../ModelProviders/ModelCustomizationTests.cs | 6 +- .../CustomizedEnum.cs | 8 ++ .../test/TypeFactoryTests.cs | 110 ++++++++++++++++++ .../Utilities/MethodProviderHelpersTests.cs | 9 +- 11 files changed, 175 insertions(+), 21 deletions(-) create mode 100644 packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/TestData/TypeFactoryTests/CreateEnum_WithCustomCodeAsExtensible_ReturnsExtensibleEnum/CustomizedEnum.cs diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/EnumProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/EnumProvider.cs index 789f58b6ef1..cf63a97c190 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/EnumProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/EnumProvider.cs @@ -21,23 +21,10 @@ public static EnumProvider Create(InputEnumType input, TypeProvider? declaringTy ? new ApiVersionEnumProvider(input, declaringType) : new FixedEnumProvider(input, declaringType); var extensibleEnumProvider = new ExtensibleEnumProvider(input, declaringType); + fixedEnumProvider.ExtensibleEnumView = extensibleEnumProvider; + extensibleEnumProvider.FixedEnumView = fixedEnumProvider; - // Check to see if there is custom code that customizes the enum. - var customCodeView = fixedEnumProvider.CustomCodeView ?? extensibleEnumProvider.CustomCodeView; - - EnumProvider provider = customCodeView switch - { - { Type: { IsValueType: true, IsStruct: true } } => extensibleEnumProvider, - { Type: { IsValueType: true, IsStruct: false } } => fixedEnumProvider, - _ => input.IsExtensible ? extensibleEnumProvider : fixedEnumProvider - }; - - if (input.Access == "public") - { - CodeModelGenerator.Instance.AddTypeToKeep(provider); - } - - return provider; + return input.IsExtensible ? extensibleEnumProvider : fixedEnumProvider; } protected EnumProvider(InputEnumType? input) @@ -47,6 +34,9 @@ protected EnumProvider(InputEnumType? input) IsExtensible = input?.IsExtensible ?? false; } + internal EnumProvider? FixedEnumView { get; set; } + internal EnumProvider? ExtensibleEnumView { get; set; } + public bool IsExtensible { get; } private bool? _isIntValue; internal bool IsIntValueType => _isIntValue ??= EnumUnderlyingType.Equals(typeof(int)) || EnumUnderlyingType.Equals(typeof(long)); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ExtensibleEnumProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ExtensibleEnumProvider.cs index 7dc2f51f752..ae937a41b99 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ExtensibleEnumProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ExtensibleEnumProvider.cs @@ -36,6 +36,7 @@ internal ExtensibleEnumProvider(InputEnumType input, TypeProvider? declaringType _valueField = new FieldProvider(FieldModifiers.Private | FieldModifiers.ReadOnly, EnumUnderlyingType, "_value", this); _declaringType = declaringType; + ExtensibleEnumView = this; } private readonly FieldProvider _valueField; diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/FixedEnumProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/FixedEnumProvider.cs index a9108091102..258c5c4d125 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/FixedEnumProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/FixedEnumProvider.cs @@ -30,6 +30,7 @@ public FixedEnumProvider(InputEnumType? input, TypeProvider? declaringType) : ba _declaringTypeProvider = declaringType; AllowedValues = input?.Values ?? []; + FixedEnumView = this; } internal IReadOnlyList AllowedValues { get; } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs index 4c71481a7b0..db54591a135 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs @@ -6,11 +6,13 @@ using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; +using Microsoft.TypeSpec.Generator.EmitterRpc; using Microsoft.TypeSpec.Generator.Expressions; using Microsoft.TypeSpec.Generator.Input; using Microsoft.TypeSpec.Generator.Primitives; using Microsoft.TypeSpec.Generator.SourceInput; using Microsoft.TypeSpec.Generator.Statements; +using Microsoft.TypeSpec.Generator.Utilities; namespace Microsoft.TypeSpec.Generator.Providers { @@ -187,7 +189,10 @@ private TypeSignatureModifiers BuildDeclarationModifiersInternal() // mask & (mask - 1) gives us 0 if mask is a power of 2, it means we have exactly one flag of above when the mask is a power of 2 if ((mask & (mask - 1)) != 0) { - throw new InvalidOperationException($"Invalid modifier {modifiers} on TypeProvider {Name}"); + CodeModelGenerator.Instance.Emitter.ReportDiagnostic( + DiagnosticCodes.InvalidAccessModifier, + $"Invalid modifiers {modifiers} detected.", + severity: EmitterDiagnosticSeverity.Warning); } // we always add partial when possible diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/TypeFactory.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/TypeFactory.cs index 705a331086a..bd6a4d8c6dc 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/TypeFactory.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/TypeFactory.cs @@ -220,6 +220,34 @@ protected internal TypeFactory() foreach (var visitor in Visitors) { enumProvider = visitor.PreVisitEnum(enumType, enumProvider); + // visit the linked enum variants + if (enumProvider is FixedEnumProvider) + { + enumProvider.ExtensibleEnumView = visitor.PreVisitEnum(enumType, enumProvider.ExtensibleEnumView); + } + else if (enumProvider is ExtensibleEnumProvider) + { + enumProvider.FixedEnumView = visitor.PreVisitEnum(enumType, enumProvider.FixedEnumView); + } + } + + if (enumProvider == null) + { + EnumCache.TryAdd(enumCacheKey, null); + return null; + } + + // Check to see if there is custom code that customizes the enum + enumProvider = enumProvider.CustomCodeView switch + { + { Type: { IsValueType: true, IsStruct: true } } => enumProvider.ExtensibleEnumView ?? enumProvider, + { Type: { IsValueType: true, IsStruct: false } } => enumProvider.FixedEnumView ?? enumProvider, + _ => enumProvider, + }; + + if (enumType.Access == "public") + { + CodeModelGenerator.Instance.AddTypeToKeep(enumProvider); } EnumCache.Add(enumCacheKey, enumProvider); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Utilities/DiagnosticCodes.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Utilities/DiagnosticCodes.cs index 0a2ff887845..d6a9292352f 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Utilities/DiagnosticCodes.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Utilities/DiagnosticCodes.cs @@ -6,5 +6,6 @@ namespace Microsoft.TypeSpec.Generator.Utilities internal static class DiagnosticCodes { public const string BaselineContractMissing = "baseline-contract-missing"; + public const string InvalidAccessModifier = "invalid-access-modifier"; } } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/InputLibraryVisitorTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/InputLibraryVisitorTests.cs index a14f7bba573..ba365ef7705 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/InputLibraryVisitorTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/InputLibraryVisitorTests.cs @@ -57,7 +57,8 @@ public void PreVisitsEnum() _mockVisitor.Object.VisitLibrary(_mockGenerator.Object.OutputLibrary); - _mockVisitor.Protected().Verify("PreVisitEnum", Times.Once(), inputEnum, ItExpr.Is(m => m.Name == EnumProvider.Create(inputEnum, null).Name)); + // enum is visited twice, one additional time for the variant created for extensible enums + _mockVisitor.Protected().Verify("PreVisitEnum", Times.Exactly(2), inputEnum, ItExpr.Is(m => m.Name == EnumProvider.Create(inputEnum, null).Name)); } [Test] diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs index 069698a0283..ae09d2e9a53 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs @@ -621,9 +621,11 @@ public async Task CanChangeEnumToExtensibleEnum() [("val1", 1), ("val2", 2), ("val3", 3)], isExtensible: false ); - var enumProvider = EnumProvider.Create(inputEnum); + var enumProvider = CodeModelGenerator.Instance.TypeFactory.CreateEnum(inputEnum); - Assert.IsTrue(enumProvider.DeclarationModifiers.HasFlag(TypeSignatureModifiers.Public | TypeSignatureModifiers.Partial | TypeSignatureModifiers.Struct | TypeSignatureModifiers.ReadOnly)); + Assert.IsNotNull(enumProvider); + Assert.IsTrue(enumProvider is ExtensibleEnumProvider); + Assert.IsTrue(enumProvider!.DeclarationModifiers.HasFlag(TypeSignatureModifiers.Public | TypeSignatureModifiers.Partial | TypeSignatureModifiers.Struct | TypeSignatureModifiers.ReadOnly)); } [Test] diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/TestData/TypeFactoryTests/CreateEnum_WithCustomCodeAsExtensible_ReturnsExtensibleEnum/CustomizedEnum.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/TestData/TypeFactoryTests/CreateEnum_WithCustomCodeAsExtensible_ReturnsExtensibleEnum/CustomizedEnum.cs new file mode 100644 index 00000000000..6d40d26ab37 --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/TestData/TypeFactoryTests/CreateEnum_WithCustomCodeAsExtensible_ReturnsExtensibleEnum/CustomizedEnum.cs @@ -0,0 +1,8 @@ +#nullable disable + +namespace Sample.SomeOtherNamespace +{ + public readonly partial struct CustomizedEnum + { + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/TypeFactoryTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/TypeFactoryTests.cs index bf6b4599624..557d08a7a7f 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/TypeFactoryTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/TypeFactoryTests.cs @@ -4,8 +4,10 @@ using System; using System.Net; using System.Text.Json; +using System.Threading.Tasks; using Microsoft.TypeSpec.Generator.Input; using Microsoft.TypeSpec.Generator.Primitives; +using Microsoft.TypeSpec.Generator.Providers; using Microsoft.TypeSpec.Generator.Tests.Common; using NUnit.Framework; @@ -191,5 +193,113 @@ public void GetCleanNameSpace_ConvertsToPascalCase(string input, string expected var actual = CodeModelGenerator.Instance.TypeFactory.GetCleanNameSpace(input); Assert.AreEqual(expected, actual); } + + [Test] + public async Task CreateEnum_WithVisitor_ChangesNamespaceToModels() + { + // Arrange - Create a fixed enum + var input = InputFactory.StringEnum( + "TestEnum", + [("value1", "value1"), ("value2", "value2")], + usage: InputModelTypeUsage.Input, + isExtensible: false); + + await MockHelpers.LoadMockGeneratorAsync(inputEnumTypes: [input]); + + // Create a visitor that modifies the namespace + var visitor = new NamespaceModifyingVisitor(); + CodeModelGenerator.Instance.AddVisitor(visitor); + + var enumProvider = CodeModelGenerator.Instance.TypeFactory.CreateEnum(input); + + Assert.IsNotNull(enumProvider); + Assert.IsTrue(enumProvider!.Type.Namespace.EndsWith(".SomeOtherNamespace")); + Assert.IsTrue(enumProvider is FixedEnumProvider); + Assert.IsNotNull(enumProvider.ExtensibleEnumView); + Assert.IsNull(enumProvider.CustomCodeView); + } + + [Test] + public async Task CreateEnum_WithCustomCodeAsExtensible_ReturnsExtensibleEnum() + { + // Arrange - Create a fixed enum in input + var inputEnum = InputFactory.StringEnum( + "CustomizedEnum", + [("value1", "value1"), ("value2", "value2")], + usage: InputModelTypeUsage.Input, + isExtensible: false); + + // Load compilation with custom code that changes the enum to extensible (struct) + await MockHelpers.LoadMockGeneratorAsync( + inputEnumTypes: [inputEnum], + compilation: async () => await Helpers.GetCompilationFromDirectoryAsync()); + + // Create a visitor that modifies the namespace + var visitor = new NamespaceModifyingVisitor(); + CodeModelGenerator.Instance.AddVisitor(visitor); + + var result = CodeModelGenerator.Instance.TypeFactory.CreateEnum(inputEnum); + + Assert.IsNotNull(result); + Assert.IsInstanceOf(result); + Assert.IsTrue(result!.Type.Namespace.EndsWith(".SomeOtherNamespace")); + } + + [Test] + public void CreateEnum_FixedEnumWithoutVisitorsOrCustomCode_ReturnsFixedEnum() + { + // Arrange - Create a fixed enum + var input = InputFactory.StringEnum( + "PlainFixedEnum", + [("value1", "value1"), ("value2", "value2")], + usage: InputModelTypeUsage.Input, + isExtensible: false); + + // Act - Create enum without any visitors or custom code modifications + var enumProvider = CodeModelGenerator.Instance.TypeFactory.CreateEnum(input); + + // Assert + Assert.IsNotNull(enumProvider); + Assert.IsInstanceOf(enumProvider); + Assert.IsFalse(enumProvider!.IsExtensible); + } + + [Test] + public void CreateEnum_ExtensibleEnumWithoutVisitorsOrCustomCode_ReturnsExtensibleEnum() + { + // Arrange - Create an extensible enum + var input = InputFactory.StringEnum( + "PlainExtensibleEnum", + [("value1", "value1"), ("value2", "value2")], + usage: InputModelTypeUsage.Input, + isExtensible: true); + + // Act - Create enum without any visitors or custom code modifications + var enumProvider = CodeModelGenerator.Instance.TypeFactory.CreateEnum(input); + + // Assert + Assert.IsNotNull(enumProvider); + Assert.IsInstanceOf(enumProvider); + Assert.IsTrue(enumProvider!.IsExtensible); + } + + /// + /// Test visitor that modifies enum namespaces to end with ".Models" + /// + private class NamespaceModifyingVisitor : LibraryVisitor + { + protected internal override EnumProvider? PreVisitEnum(InputEnumType enumType, EnumProvider? type) + { + if (type == null) + return type; + + // Create a new enum provider with modified namespace + // replace ".Models" with ".SomeOtherNamespace" + var updatedNamespace = type.Type.Namespace.Replace(".Models", ".SomeOtherNamespace"); + type.Update(@namespace: updatedNamespace); + + return type; + } + } } } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Utilities/MethodProviderHelpersTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Utilities/MethodProviderHelpersTests.cs index 98084a7c126..9a158c9e9b7 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Utilities/MethodProviderHelpersTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Utilities/MethodProviderHelpersTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. using System.Collections.Generic; @@ -12,6 +12,13 @@ namespace Microsoft.TypeSpec.Generator.Tests.Utilities { public class MethodProviderHelpersTests { + + [SetUp] + public void Setup() + { + MockHelpers.LoadMockGenerator(); + } + [Test] public void BuildXmlDocsAddsCorrectExceptions() { From 4cf169f2cd6269c637168a5063ad30eded172e01 Mon Sep 17 00:00:00 2001 From: Brian Terlson Date: Fri, 12 Dec 2025 14:01:07 -0800 Subject: [PATCH 35/40] Alloy 0.22 (#9202) Mostly whitespace changes on account of random empty things not making newlines anymore. --- .../changes/alloy-0.22-2025-11-12-13-21-52.md | 10 ++ packages/emitter-framework/package.json | 12 +- .../components/class/declaration.test.tsx | 35 +---- .../components/enum/declaration.test.tsx | 5 +- .../json-converter-resolver.test.tsx | 1 - .../components/property/property.test.tsx | 1 - .../components/type-expression.test.tsx | 5 +- .../components/interface-declaration.test.tsx | 10 +- packages/http-client-js/package.json | 6 +- .../src/components/http-request.tsx | 3 +- .../test/scenarios/auth/basic_auth.md | 1 - .../test/scenarios/auth/bearer.md | 1 - .../test/scenarios/auth/client_parameters.md | 1 - .../test/scenarios/auth/key_credential.md | 1 - .../test/scenarios/auth/oauth2.md | 1 - .../scenarios/auth/sub_client_override.md | 2 - .../test/scenarios/client/dotted_namespace.md | 1 - .../test/scenarios/client/global_namespace.md | 1 - .../client/multiple_top_level_clients.md | 2 - .../test/scenarios/client/nested_client.md | 1 - .../test/scenarios/http-operations/basic.md | 1 - .../test/scenarios/http-operations/paging.md | 2 - .../http-operations/with-parameters.md | 1 - .../body_root_anonymous.md | 1 - .../constant_as_optional.md | 1 - .../default_value_as_optional.md | 1 - .../operation-parameters/no_content_type.md | 1 - .../operation-parameters/no_parameters.md | 1 - .../operation-parameters/only_optional.md | 1 - .../operation-parameters/only_required.md | 1 - .../operation-parameters/reserved_names.md | 1 - .../operation-parameters/spread_body.md | 1 - .../spread_with_nested.md | 1 - .../operation-parameters/union_body.md | 1 - .../with_body_property.md | 1 - .../operation-parameters/with_body_root.md | 1 - packages/http-client/package.json | 10 +- packages/tspd/package.json | 8 +- pnpm-lock.yaml | 134 +++++++++++------- pnpm-workspace.yaml | 2 + 40 files changed, 127 insertions(+), 144 deletions(-) create mode 100644 .chronus/changes/alloy-0.22-2025-11-12-13-21-52.md diff --git a/.chronus/changes/alloy-0.22-2025-11-12-13-21-52.md b/.chronus/changes/alloy-0.22-2025-11-12-13-21-52.md new file mode 100644 index 00000000000..723a280c815 --- /dev/null +++ b/.chronus/changes/alloy-0.22-2025-11-12-13-21-52.md @@ -0,0 +1,10 @@ +--- +changeKind: dependencies +packages: + - "@typespec/emitter-framework" + - "@typespec/http-client-js" + - "@typespec/http-client" + - "@typespec/tspd" +--- + +Update to alloy 0.22 \ No newline at end of file diff --git a/packages/emitter-framework/package.json b/packages/emitter-framework/package.json index 3d2caecb5d7..3dc777012e5 100644 --- a/packages/emitter-framework/package.json +++ b/packages/emitter-framework/package.json @@ -55,16 +55,16 @@ "license": "MIT", "description": "", "peerDependencies": { - "@alloy-js/core": "^0.21.0", - "@alloy-js/csharp": "^0.21.0", - "@alloy-js/typescript": "^0.21.0", + "@alloy-js/core": "^0.22.0", + "@alloy-js/csharp": "^0.22.0", + "@alloy-js/typescript": "^0.22.0", "@typespec/compiler": "workspace:^" }, "devDependencies": { - "@alloy-js/cli": "^0.21.0", - "@alloy-js/core": "^0.21.0", + "@alloy-js/cli": "^0.22.0", + "@alloy-js/core": "^0.22.0", "@alloy-js/rollup-plugin": "^0.1.0", - "@alloy-js/typescript": "^0.21.0", + "@alloy-js/typescript": "^0.22.0", "@typespec/compiler": "workspace:^", "concurrently": "^9.1.2", "pathe": "^2.0.3", diff --git a/packages/emitter-framework/src/csharp/components/class/declaration.test.tsx b/packages/emitter-framework/src/csharp/components/class/declaration.test.tsx index 7a088c4fe4f..3f008f01893 100644 --- a/packages/emitter-framework/src/csharp/components/class/declaration.test.tsx +++ b/packages/emitter-framework/src/csharp/components/class/declaration.test.tsx @@ -36,10 +36,7 @@ it("renders an empty class declaration", async () => { , ).toRenderTo(` - class TestModel - { - - } + class TestModel {} `); }); @@ -88,14 +85,8 @@ it("renders a class declaration with properties using component override", async , ).toRenderTo(d` - class Foo - { - - } - class Bar - { - - } + class Foo {} + class Bar {} class TestModel { public required string Prop1 { get; set; } @@ -150,10 +141,7 @@ it("can override class name", async () => { , ).toRenderTo(` - class CustomClassName - { - - } + class CustomClassName {} `); }); @@ -168,10 +156,7 @@ it("renders a class with access modifiers", async () => { , ).toRenderTo(` - protected class TestModel - { - - } + protected class TestModel {} `); }); @@ -187,10 +172,7 @@ describe("from an interface", () => { , ).toRenderTo(` - class TestInterface - { - - } + class TestInterface {} `); }); @@ -229,10 +211,7 @@ it("renders a class with model members", async () => { , ).toRenderTo(` - class TestReference - { - - } + class TestReference {} class TestModel { public required TestReference Prop1 { get; set; } diff --git a/packages/emitter-framework/src/csharp/components/enum/declaration.test.tsx b/packages/emitter-framework/src/csharp/components/enum/declaration.test.tsx index a42039bb410..82b189d9eec 100644 --- a/packages/emitter-framework/src/csharp/components/enum/declaration.test.tsx +++ b/packages/emitter-framework/src/csharp/components/enum/declaration.test.tsx @@ -54,10 +54,7 @@ it("renders an empty enum declaration", async () => { , ).toRenderTo(` - enum TestEnum - { - - } + enum TestEnum {} `); }); diff --git a/packages/emitter-framework/src/csharp/components/json-converter/json-converter-resolver.test.tsx b/packages/emitter-framework/src/csharp/components/json-converter/json-converter-resolver.test.tsx index 2c64392835b..b62c901ba15 100644 --- a/packages/emitter-framework/src/csharp/components/json-converter/json-converter-resolver.test.tsx +++ b/packages/emitter-framework/src/csharp/components/json-converter/json-converter-resolver.test.tsx @@ -104,7 +104,6 @@ it("Resolve custom converter", async () => { [JsonConverter(typeof(FakeJsonConverter))] public required string Prop1 { get; set; } - internal sealed class FakeJsonConverter : JsonConverter { public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) diff --git a/packages/emitter-framework/src/csharp/components/property/property.test.tsx b/packages/emitter-framework/src/csharp/components/property/property.test.tsx index 7444028b58e..1ebf1bf380d 100644 --- a/packages/emitter-framework/src/csharp/components/property/property.test.tsx +++ b/packages/emitter-framework/src/csharp/components/property/property.test.tsx @@ -233,7 +233,6 @@ describe("jsonAttributes", () => { [JsonConverter(typeof(TimeSpanIso8601JsonConverter))] public required TimeSpan Prop3 { get; set; } - // JsonConverter wont work as nested class, but good enough for test to verify the generated code. internal sealed class TimeSpanSecondsInt32JsonConverter : JsonConverter { diff --git a/packages/emitter-framework/src/csharp/components/type-expression.test.tsx b/packages/emitter-framework/src/csharp/components/type-expression.test.tsx index 5ef7e879fff..8a6354aa648 100644 --- a/packages/emitter-framework/src/csharp/components/type-expression.test.tsx +++ b/packages/emitter-framework/src/csharp/components/type-expression.test.tsx @@ -87,10 +87,7 @@ describe("Record map to IDictionary", () => { , ).toRenderTo(` - class Pet - { - - } + class Pet {} IDictionary `); }); diff --git a/packages/emitter-framework/test/typescript/components/interface-declaration.test.tsx b/packages/emitter-framework/test/typescript/components/interface-declaration.test.tsx index df1be061b03..7d350ed434d 100644 --- a/packages/emitter-framework/test/typescript/components/interface-declaration.test.tsx +++ b/packages/emitter-framework/test/typescript/components/interface-declaration.test.tsx @@ -213,9 +213,7 @@ describe("Typescript Interface", () => { , ).toRenderTo(` - export interface Foo extends Array { - - }`); + export interface Foo extends Array {}`); }); it("creates an interface for a model that 'is' a record ", async () => { @@ -223,7 +221,7 @@ describe("Typescript Interface", () => { namespace DemoService; model Foo is Record; - `); + `); const [namespace] = program.resolveTypeReference("DemoService"); const models = (namespace as Namespace).models; @@ -421,9 +419,7 @@ describe("Typescript Interface", () => { , ).toRenderTo(` - export interface Widget { - - }`); + export interface Widget {}`); }); it("can override interface name", async () => { diff --git a/packages/http-client-js/package.json b/packages/http-client-js/package.json index 4c544e9eafe..1ae36852252 100644 --- a/packages/http-client-js/package.json +++ b/packages/http-client-js/package.json @@ -53,14 +53,14 @@ "@typespec/rest": "workspace:^" }, "dependencies": { - "@alloy-js/core": "^0.21.0", - "@alloy-js/typescript": "^0.21.0", + "@alloy-js/core": "^0.22.0", + "@alloy-js/typescript": "^0.22.0", "@typespec/emitter-framework": "workspace:^", "@typespec/http-client": "workspace:^", "prettier": "~3.6.2" }, "devDependencies": { - "@alloy-js/cli": "^0.21.0", + "@alloy-js/cli": "^0.22.0", "@alloy-js/rollup-plugin": "^0.1.0", "@types/yargs": "~17.0.33", "@typespec/http": "workspace:^", diff --git a/packages/http-client-js/src/components/http-request.tsx b/packages/http-client-js/src/components/http-request.tsx index 5a9cebcc116..c7442aaac8e 100644 --- a/packages/http-client-js/src/components/http-request.tsx +++ b/packages/http-client-js/src/components/http-request.tsx @@ -38,8 +38,9 @@ export function HttpRequest(props: HttpRequestProps) { await client.pathUnchecked(${()}).${verb}(${()}) `} - + + {code` if (typeof options?.operationOptions?.onResponse === "function") { options?.operationOptions?.onResponse(response); diff --git a/packages/http-client-js/test/scenarios/auth/basic_auth.md b/packages/http-client-js/test/scenarios/auth/basic_auth.md index 34465b805ac..8da8fb1dae9 100644 --- a/packages/http-client-js/test/scenarios/auth/basic_auth.md +++ b/packages/http-client-js/test/scenarios/auth/basic_auth.md @@ -25,7 +25,6 @@ The client signature should include a positional parameter for credential of typ ```ts src/testClient.ts class TestClient export class TestClient { #context: TestClientContext; - constructor(endpoint: string, credential: BasicCredential, options?: TestClientOptions) { this.#context = createTestClientContext(endpoint, credential, options); } diff --git a/packages/http-client-js/test/scenarios/auth/bearer.md b/packages/http-client-js/test/scenarios/auth/bearer.md index 800db6476af..85a5fe5acdd 100644 --- a/packages/http-client-js/test/scenarios/auth/bearer.md +++ b/packages/http-client-js/test/scenarios/auth/bearer.md @@ -25,7 +25,6 @@ The client signature should include a positional parameter for credential of typ ```ts src/testClient.ts class TestClient export class TestClient { #context: TestClientContext; - constructor(endpoint: string, credential: BasicCredential, options?: TestClientOptions) { this.#context = createTestClientContext(endpoint, credential, options); } diff --git a/packages/http-client-js/test/scenarios/auth/client_parameters.md b/packages/http-client-js/test/scenarios/auth/client_parameters.md index 1051a2b4ab6..4ef2c1b08bd 100644 --- a/packages/http-client-js/test/scenarios/auth/client_parameters.md +++ b/packages/http-client-js/test/scenarios/auth/client_parameters.md @@ -26,7 +26,6 @@ TODO: Revisit if we need additional types since it will be difficult at runtime ```ts src/testClient.ts class TestClient export class TestClient { #context: TestClientContext; - constructor( endpoint: string, credential: BearerTokenCredential | ApiKeyCredential, diff --git a/packages/http-client-js/test/scenarios/auth/key_credential.md b/packages/http-client-js/test/scenarios/auth/key_credential.md index 470edddd234..df9bfae4f77 100644 --- a/packages/http-client-js/test/scenarios/auth/key_credential.md +++ b/packages/http-client-js/test/scenarios/auth/key_credential.md @@ -25,7 +25,6 @@ The client signature should include a positional parameter for credential of typ ```ts src/testClient.ts class TestClient export class TestClient { #context: TestClientContext; - constructor(endpoint: string, credential: ApiKeyCredential, options?: TestClientOptions) { this.#context = createTestClientContext(endpoint, credential, options); } diff --git a/packages/http-client-js/test/scenarios/auth/oauth2.md b/packages/http-client-js/test/scenarios/auth/oauth2.md index 7ea211f6c05..84ba781ce97 100644 --- a/packages/http-client-js/test/scenarios/auth/oauth2.md +++ b/packages/http-client-js/test/scenarios/auth/oauth2.md @@ -36,7 +36,6 @@ The client signature should include a positional parameter for credential of typ ```ts src/testClient.ts class TestClient export class TestClient { #context: TestClientContext; - constructor( endpoint: string, credential: OAuth2TokenCredential, diff --git a/packages/http-client-js/test/scenarios/auth/sub_client_override.md b/packages/http-client-js/test/scenarios/auth/sub_client_override.md index 1a3f7169e86..52aba4b8632 100644 --- a/packages/http-client-js/test/scenarios/auth/sub_client_override.md +++ b/packages/http-client-js/test/scenarios/auth/sub_client_override.md @@ -34,7 +34,6 @@ The subclient is not a child of the TestClient because they have different param ```ts src/testClient.ts class TestClient export class TestClient { #context: TestClientContext; - constructor(endpoint: string, credential: BasicCredential, options?: TestClientOptions) { this.#context = createTestClientContext(endpoint, credential, options); } @@ -49,7 +48,6 @@ The sub client shouldn't take a credential ```ts src/testClient.ts class SubClient export class SubClient { #context: SubClientContext; - constructor(endpoint: string, options?: SubClientOptions) { this.#context = createSubClientContext(endpoint, options); } diff --git a/packages/http-client-js/test/scenarios/client/dotted_namespace.md b/packages/http-client-js/test/scenarios/client/dotted_namespace.md index 79e5f707fad..0da7b1dc184 100644 --- a/packages/http-client-js/test/scenarios/client/dotted_namespace.md +++ b/packages/http-client-js/test/scenarios/client/dotted_namespace.md @@ -17,7 +17,6 @@ The client should match the last namespace. ```ts src/bazClient.ts class BazClient export class BazClient { #context: BazClientContext; - constructor(endpoint: string, options?: BazClientOptions) { this.#context = createBazClientContext(endpoint, options); } diff --git a/packages/http-client-js/test/scenarios/client/global_namespace.md b/packages/http-client-js/test/scenarios/client/global_namespace.md index 9ab813600c4..48257ec6a84 100644 --- a/packages/http-client-js/test/scenarios/client/global_namespace.md +++ b/packages/http-client-js/test/scenarios/client/global_namespace.md @@ -39,7 +39,6 @@ It should generate a client for the Global Namespace with a single operation `fo ```ts src/client.ts class Client export class Client { #context: ClientContext; - constructor(endpoint: string, options?: ClientOptions) { this.#context = createClientContext(endpoint, options); } diff --git a/packages/http-client-js/test/scenarios/client/multiple_top_level_clients.md b/packages/http-client-js/test/scenarios/client/multiple_top_level_clients.md index a108db64671..f33492f9597 100644 --- a/packages/http-client-js/test/scenarios/client/multiple_top_level_clients.md +++ b/packages/http-client-js/test/scenarios/client/multiple_top_level_clients.md @@ -37,7 +37,6 @@ import { get, type GetOptions } from "./api/fooClientOperations.js"; export class FooClient { #context: FooClientContext; - constructor(endpoint: string, options?: FooClientOptions) { this.#context = createFooClientContext(endpoint, options); } @@ -60,7 +59,6 @@ import type { BarItem } from "./models/models.js"; export class BarClient { #context: BarClientContext; - constructor(endpoint: string, options?: BarClientOptions) { this.#context = createBarClientContext(endpoint, options); } diff --git a/packages/http-client-js/test/scenarios/client/nested_client.md b/packages/http-client-js/test/scenarios/client/nested_client.md index f24b96f2b46..e7fdcaf3505 100644 --- a/packages/http-client-js/test/scenarios/client/nested_client.md +++ b/packages/http-client-js/test/scenarios/client/nested_client.md @@ -77,7 +77,6 @@ export class DemoServiceClient { } export class WidgetsClient { #context: WidgetsClientContext; - constructor(endpoint: string, options?: WidgetsClientOptions) { this.#context = createWidgetsClientContext(endpoint, options); } diff --git a/packages/http-client-js/test/scenarios/http-operations/basic.md b/packages/http-client-js/test/scenarios/http-operations/basic.md index 4b9d150286c..5ba7ab7591a 100644 --- a/packages/http-client-js/test/scenarios/http-operations/basic.md +++ b/packages/http-client-js/test/scenarios/http-operations/basic.md @@ -32,7 +32,6 @@ import { foo, type FooOptions } from "./api/testClientOperations.js"; export class TestClient { #context: TestClientContext; - constructor(endpoint: string, options?: TestClientOptions) { this.#context = createTestClientContext(endpoint, options); } diff --git a/packages/http-client-js/test/scenarios/http-operations/paging.md b/packages/http-client-js/test/scenarios/http-operations/paging.md index e9f1924cf88..4d763b04685 100644 --- a/packages/http-client-js/test/scenarios/http-operations/paging.md +++ b/packages/http-client-js/test/scenarios/http-operations/paging.md @@ -110,7 +110,6 @@ export interface LinkPageResponse { ```ts src/testClient.ts class TestClient export class TestClient { #context: TestClientContext; - constructor(endpoint: string, options?: TestClientOptions) { this.#context = createTestClientContext(endpoint, options); } @@ -233,7 +232,6 @@ export interface LinkPageResponse { ```ts src/testClient.ts class TestClient export class TestClient { #context: TestClientContext; - constructor(endpoint: string, options?: TestClientOptions) { this.#context = createTestClientContext(endpoint, options); } diff --git a/packages/http-client-js/test/scenarios/http-operations/with-parameters.md b/packages/http-client-js/test/scenarios/http-operations/with-parameters.md index bdc9c55edc9..b9fd5d5daa3 100644 --- a/packages/http-client-js/test/scenarios/http-operations/with-parameters.md +++ b/packages/http-client-js/test/scenarios/http-operations/with-parameters.md @@ -68,7 +68,6 @@ It should generate the client class with the read operation that calls the opera ```ts src/demoServiceClient.ts class WidgetsClient export class WidgetsClient { #context: WidgetsClientContext; - constructor(endpoint: string, options?: WidgetsClientOptions) { this.#context = createWidgetsClientContext(endpoint, options); } diff --git a/packages/http-client-js/test/scenarios/operation-parameters/body_root_anonymous.md b/packages/http-client-js/test/scenarios/operation-parameters/body_root_anonymous.md index 79e3e6f48fd..a33507c5ff6 100644 --- a/packages/http-client-js/test/scenarios/operation-parameters/body_root_anonymous.md +++ b/packages/http-client-js/test/scenarios/operation-parameters/body_root_anonymous.md @@ -69,7 +69,6 @@ export interface CreateOptions extends OperationOptions { ```ts src/testClient.ts class TestClient export class TestClient { #context: TestClientContext; - constructor(endpoint: string, options?: TestClientOptions) { this.#context = createTestClientContext(endpoint, options); } diff --git a/packages/http-client-js/test/scenarios/operation-parameters/constant_as_optional.md b/packages/http-client-js/test/scenarios/operation-parameters/constant_as_optional.md index 5e14c5d5961..6fbcd3786f6 100644 --- a/packages/http-client-js/test/scenarios/operation-parameters/constant_as_optional.md +++ b/packages/http-client-js/test/scenarios/operation-parameters/constant_as_optional.md @@ -44,7 +44,6 @@ export interface GetOptions extends OperationOptions { ```ts src/testClient.ts class TestClient export class TestClient { #context: TestClientContext; - constructor(endpoint: string, options?: TestClientOptions) { this.#context = createTestClientContext(endpoint, options); } diff --git a/packages/http-client-js/test/scenarios/operation-parameters/default_value_as_optional.md b/packages/http-client-js/test/scenarios/operation-parameters/default_value_as_optional.md index 009316bc196..ce338a13366 100644 --- a/packages/http-client-js/test/scenarios/operation-parameters/default_value_as_optional.md +++ b/packages/http-client-js/test/scenarios/operation-parameters/default_value_as_optional.md @@ -44,7 +44,6 @@ export interface GetOptions extends OperationOptions { ```ts src/testClient.ts class TestClient export class TestClient { #context: TestClientContext; - constructor(endpoint: string, options?: TestClientOptions) { this.#context = createTestClientContext(endpoint, options); } diff --git a/packages/http-client-js/test/scenarios/operation-parameters/no_content_type.md b/packages/http-client-js/test/scenarios/operation-parameters/no_content_type.md index 2953761e8d2..85297018a60 100644 --- a/packages/http-client-js/test/scenarios/operation-parameters/no_content_type.md +++ b/packages/http-client-js/test/scenarios/operation-parameters/no_content_type.md @@ -52,7 +52,6 @@ export interface GetOptions extends OperationOptions {} ```ts src/testClient.ts class TestClient export class TestClient { #context: TestClientContext; - constructor(endpoint: string, options?: TestClientOptions) { this.#context = createTestClientContext(endpoint, options); } diff --git a/packages/http-client-js/test/scenarios/operation-parameters/no_parameters.md b/packages/http-client-js/test/scenarios/operation-parameters/no_parameters.md index 5a0535ad286..a3397119395 100644 --- a/packages/http-client-js/test/scenarios/operation-parameters/no_parameters.md +++ b/packages/http-client-js/test/scenarios/operation-parameters/no_parameters.md @@ -40,7 +40,6 @@ export interface GetOptions extends OperationOptions {} ```ts src/testClient.ts class TestClient export class TestClient { #context: TestClientContext; - constructor(endpoint: string, options?: TestClientOptions) { this.#context = createTestClientContext(endpoint, options); } diff --git a/packages/http-client-js/test/scenarios/operation-parameters/only_optional.md b/packages/http-client-js/test/scenarios/operation-parameters/only_optional.md index b649326c3fa..3f5410bc972 100644 --- a/packages/http-client-js/test/scenarios/operation-parameters/only_optional.md +++ b/packages/http-client-js/test/scenarios/operation-parameters/only_optional.md @@ -52,7 +52,6 @@ export interface GetWithParamsOptions extends OperationOptions { ```ts src/testClient.ts class TestClient export class TestClient { #context: TestClientContext; - constructor(endpoint: string, options?: TestClientOptions) { this.#context = createTestClientContext(endpoint, options); } diff --git a/packages/http-client-js/test/scenarios/operation-parameters/only_required.md b/packages/http-client-js/test/scenarios/operation-parameters/only_required.md index 0c475bd1ce1..28e21c83cd9 100644 --- a/packages/http-client-js/test/scenarios/operation-parameters/only_required.md +++ b/packages/http-client-js/test/scenarios/operation-parameters/only_required.md @@ -48,7 +48,6 @@ export interface GetWithParamsOptions extends OperationOptions {} ```ts src/testClient.ts class TestClient export class TestClient { #context: TestClientContext; - constructor(endpoint: string, options?: TestClientOptions) { this.#context = createTestClientContext(endpoint, options); } diff --git a/packages/http-client-js/test/scenarios/operation-parameters/reserved_names.md b/packages/http-client-js/test/scenarios/operation-parameters/reserved_names.md index 6ee94d107a1..931bea77237 100644 --- a/packages/http-client-js/test/scenarios/operation-parameters/reserved_names.md +++ b/packages/http-client-js/test/scenarios/operation-parameters/reserved_names.md @@ -50,7 +50,6 @@ export interface GetOptions extends OperationOptions { ```ts src/testClient.ts class TestClient export class TestClient { #context: TestClientContext; - constructor(endpoint: string, options?: TestClientOptions) { this.#context = createTestClientContext(endpoint, options); } diff --git a/packages/http-client-js/test/scenarios/operation-parameters/spread_body.md b/packages/http-client-js/test/scenarios/operation-parameters/spread_body.md index f4aa2d4c3cf..424ac373a05 100644 --- a/packages/http-client-js/test/scenarios/operation-parameters/spread_body.md +++ b/packages/http-client-js/test/scenarios/operation-parameters/spread_body.md @@ -60,7 +60,6 @@ export interface CreateOptions extends OperationOptions { ```ts src/testClient.ts class TestClient export class TestClient { #context: TestClientContext; - constructor(endpoint: string, options?: TestClientOptions) { this.#context = createTestClientContext(endpoint, options); } diff --git a/packages/http-client-js/test/scenarios/operation-parameters/spread_with_nested.md b/packages/http-client-js/test/scenarios/operation-parameters/spread_with_nested.md index 625857d074f..800259148a7 100644 --- a/packages/http-client-js/test/scenarios/operation-parameters/spread_with_nested.md +++ b/packages/http-client-js/test/scenarios/operation-parameters/spread_with_nested.md @@ -72,7 +72,6 @@ export interface CreateOptions extends OperationOptions { ```ts src/testClient.ts class TestClient export class TestClient { #context: TestClientContext; - constructor(endpoint: string, options?: TestClientOptions) { this.#context = createTestClientContext(endpoint, options); } diff --git a/packages/http-client-js/test/scenarios/operation-parameters/union_body.md b/packages/http-client-js/test/scenarios/operation-parameters/union_body.md index 8e343c58270..725af219159 100644 --- a/packages/http-client-js/test/scenarios/operation-parameters/union_body.md +++ b/packages/http-client-js/test/scenarios/operation-parameters/union_body.md @@ -64,7 +64,6 @@ export interface SendOptions extends OperationOptions {} ```ts src/testClient.ts class TestClient export class TestClient { #context: TestClientContext; - constructor(endpoint: string, options?: TestClientOptions) { this.#context = createTestClientContext(endpoint, options); } diff --git a/packages/http-client-js/test/scenarios/operation-parameters/with_body_property.md b/packages/http-client-js/test/scenarios/operation-parameters/with_body_property.md index bb49188b003..ff0787efd73 100644 --- a/packages/http-client-js/test/scenarios/operation-parameters/with_body_property.md +++ b/packages/http-client-js/test/scenarios/operation-parameters/with_body_property.md @@ -57,7 +57,6 @@ export interface CreateOptions extends OperationOptions { ```ts src/testClient.ts class TestClient export class TestClient { #context: TestClientContext; - constructor(endpoint: string, options?: TestClientOptions) { this.#context = createTestClientContext(endpoint, options); } diff --git a/packages/http-client-js/test/scenarios/operation-parameters/with_body_root.md b/packages/http-client-js/test/scenarios/operation-parameters/with_body_root.md index bca7fc7ac98..a9f651a40cf 100644 --- a/packages/http-client-js/test/scenarios/operation-parameters/with_body_root.md +++ b/packages/http-client-js/test/scenarios/operation-parameters/with_body_root.md @@ -59,7 +59,6 @@ export interface CreateOptions extends OperationOptions { ```ts src/testClient.ts class TestClient export class TestClient { #context: TestClientContext; - constructor(endpoint: string, options?: TestClientOptions) { this.#context = createTestClientContext(endpoint, options); } diff --git a/packages/http-client/package.json b/packages/http-client/package.json index f7491d2b854..23021b990b9 100644 --- a/packages/http-client/package.json +++ b/packages/http-client/package.json @@ -23,17 +23,17 @@ } }, "peerDependencies": { - "@alloy-js/core": "^0.21.0", - "@alloy-js/typescript": "^0.21.0", + "@alloy-js/core": "^0.22.0", + "@alloy-js/typescript": "^0.22.0", "@typespec/compiler": "workspace:^", "@typespec/emitter-framework": "workspace:^", "@typespec/http": "workspace:^" }, "devDependencies": { - "@alloy-js/cli": "^0.21.0", - "@alloy-js/core": "^0.21.0", + "@alloy-js/cli": "^0.22.0", + "@alloy-js/core": "^0.22.0", "@alloy-js/rollup-plugin": "^0.1.0", - "@alloy-js/typescript": "^0.21.0", + "@alloy-js/typescript": "^0.22.0", "@types/node": "~24.10.1", "@typespec/compiler": "workspace:^", "@typespec/emitter-framework": "workspace:^", diff --git a/packages/tspd/package.json b/packages/tspd/package.json index 70fa6800950..39b982eb3e2 100644 --- a/packages/tspd/package.json +++ b/packages/tspd/package.json @@ -55,9 +55,9 @@ "!dist/test/**" ], "dependencies": { - "@alloy-js/core": "^0.21.0", - "@alloy-js/markdown": "^0.21.0", - "@alloy-js/typescript": "^0.21.0", + "@alloy-js/core": "^0.22.0", + "@alloy-js/markdown": "^0.22.0", + "@alloy-js/typescript": "^0.22.0", "@microsoft/api-extractor": "^7.52.1", "@microsoft/api-extractor-model": "^7.30.6", "@microsoft/tsdoc": "^0.16.0", @@ -71,7 +71,7 @@ "yargs": "~18.0.0" }, "devDependencies": { - "@alloy-js/cli": "^0.21.0", + "@alloy-js/cli": "^0.22.0", "@alloy-js/rollup-plugin": "^0.1.0", "@types/node": "~24.10.1", "@types/yargs": "~17.0.33", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d38e971f4e6..998b41bd937 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -412,21 +412,21 @@ importers: packages/emitter-framework: dependencies: '@alloy-js/csharp': - specifier: ^0.21.0 - version: 0.21.0 + specifier: ^0.22.0 + version: 0.22.0 devDependencies: '@alloy-js/cli': - specifier: ^0.21.0 - version: 0.21.0 + specifier: ^0.22.0 + version: 0.22.0 '@alloy-js/core': - specifier: ^0.21.0 - version: 0.21.0 + specifier: ^0.22.0 + version: 0.22.0 '@alloy-js/rollup-plugin': specifier: ^0.1.0 version: 0.1.0(@babel/core@7.28.5)(@types/babel__core@7.20.5)(rollup@4.49.0) '@alloy-js/typescript': - specifier: ^0.21.0 - version: 0.21.0 + specifier: ^0.22.0 + version: 0.22.0 '@typespec/compiler': specifier: workspace:^ version: link:../compiler @@ -680,17 +680,17 @@ importers: packages/http-client: devDependencies: '@alloy-js/cli': - specifier: ^0.21.0 - version: 0.21.0 + specifier: ^0.22.0 + version: 0.22.0 '@alloy-js/core': - specifier: ^0.21.0 - version: 0.21.0 + specifier: ^0.22.0 + version: 0.22.0 '@alloy-js/rollup-plugin': specifier: ^0.1.0 version: 0.1.0(@babel/core@7.28.5)(@types/babel__core@7.20.5)(rollup@4.49.0) '@alloy-js/typescript': - specifier: ^0.21.0 - version: 0.21.0 + specifier: ^0.22.0 + version: 0.22.0 '@types/node': specifier: ~24.10.1 version: 24.10.1 @@ -725,11 +725,11 @@ importers: packages/http-client-js: dependencies: '@alloy-js/core': - specifier: ^0.21.0 - version: 0.21.0 + specifier: ^0.22.0 + version: 0.22.0 '@alloy-js/typescript': - specifier: ^0.21.0 - version: 0.21.0 + specifier: ^0.22.0 + version: 0.22.0 '@typespec/compiler': specifier: workspace:^ version: link:../compiler @@ -747,8 +747,8 @@ importers: version: 3.6.2 devDependencies: '@alloy-js/cli': - specifier: ^0.21.0 - version: 0.21.0 + specifier: ^0.22.0 + version: 0.22.0 '@alloy-js/rollup-plugin': specifier: ^0.1.0 version: 0.1.0(@babel/core@7.28.5)(@types/babel__core@7.20.5)(rollup@4.49.0) @@ -2260,14 +2260,14 @@ importers: packages/tspd: dependencies: '@alloy-js/core': - specifier: ^0.21.0 - version: 0.21.0 + specifier: ^0.22.0 + version: 0.22.0 '@alloy-js/markdown': - specifier: ^0.21.0 - version: 0.21.0 + specifier: ^0.22.0 + version: 0.22.0 '@alloy-js/typescript': - specifier: ^0.21.0 - version: 0.21.0 + specifier: ^0.22.0 + version: 0.22.0 '@microsoft/api-extractor': specifier: ^7.52.1 version: 7.55.0(@types/node@24.10.1) @@ -2303,8 +2303,8 @@ importers: version: 18.0.0 devDependencies: '@alloy-js/cli': - specifier: ^0.21.0 - version: 0.21.0 + specifier: ^0.22.0 + version: 0.22.0 '@alloy-js/rollup-plugin': specifier: ^0.1.0 version: 0.1.0(@babel/core@7.28.5)(@types/babel__core@7.20.5)(rollup@4.49.0) @@ -2712,29 +2712,29 @@ packages: '@alloy-js/babel-preset@0.2.1': resolution: {integrity: sha512-vz9kvQwx5qBzHIw4ryqUaQqpgNOMBmkdDcV3e2zZfMq8Pp16ePFtvviHh6RwyLcvXQQClex3ZZy8ON9TifMnxw==} - '@alloy-js/cli@0.21.0': - resolution: {integrity: sha512-k1Rf6kbYPdMKYJ1pFmhbk0NpW7p/aL/HbmxpJxmF/tbXAhZmNO62f9JM4qF64jNnq9byq31PMBSOIAIZFLqa1A==} + '@alloy-js/cli@0.22.0': + resolution: {integrity: sha512-M9XeHxdSRIZnwCZrYkOIuLrQQfxyTuc7tJrMjJdOFgvShBjwZJG21iFhvvYp5Reeq+GFEbuGlviho3GSxd7szA==} engines: {node: '>=18.0.0'} hasBin: true - '@alloy-js/core@0.21.0': - resolution: {integrity: sha512-eIBllm+Lgk/AcV6QdipZAVlYPIp6RHmgz046GXBQeXZnTZXmPHURVFI18/FVuaK7K+uUt0eriPXIYXs4/Ja5rQ==} + '@alloy-js/core@0.22.0': + resolution: {integrity: sha512-cqa6CL2m3zfPXF64Zr7WIqOpSWyqFi7ojQJVzpMjOsb1zJhoQzKt28/FCI6++Na4QDeSynOmWGEvHZ7CDYXn4w==} - '@alloy-js/csharp@0.21.0': - resolution: {integrity: sha512-Tw3AQaHjwRTZB6L6QPoXFJOmjDQyyGb2gwwAKGnea7q/J6BmwNkBHvCSuVe21Nkhgb4/upivWFyP8zbtdVAE5A==} + '@alloy-js/csharp@0.22.0': + resolution: {integrity: sha512-3m0HveXIgR3hScVMZbG1y264YTgvDuSeZqR1ARTsk05RR6YUD/7MFxJd5IiT4fOYePgROWO7CuBllrTexfj0Yg==} - '@alloy-js/markdown@0.21.0': - resolution: {integrity: sha512-Er2aqWdolajWUrHxeqZoiK/Grdet2zaEr8ZtIbvv/M0sMz975p0ltijZNF3OnMde0wFlk1Jg14hkiitI9wFVgQ==} + '@alloy-js/markdown@0.22.0': + resolution: {integrity: sha512-VslLzyk9780MaEAKH/9LE7dPcxIxHEx/V3+MsoZ8nHK+rvpmnTblxFJpbkLvmhUf8Oq2hmgsvfv7jIauBGI0rQ==} - '@alloy-js/msbuild@0.21.0': - resolution: {integrity: sha512-QmMwF7eoYMdR5mX+8cIKb5F3Mgi3uQlFYrGYq92ht6BOc/XKyBXIwCXq6zqPMAT7nd2BHDD2hvgbL6nLS4QcGg==} + '@alloy-js/msbuild@0.22.0': + resolution: {integrity: sha512-Zi4bezFzQveW4u78qwSlIlscZd8y5OKCRitSOAiw0qLfF95L4+3wgQ6QpbYuqeRRZIa5kimhbogKTSrSxycrUg==} '@alloy-js/rollup-plugin@0.1.0': resolution: {integrity: sha512-MXR8mBdSh/pxMP8kIXAcMYKsm5yOWZ+igxcaRX1vBXFiHU4eK7gE/5q6Fk8Vdydh+MItWtgekwIhUWvcszdNFQ==} engines: {node: '>=18.0.0'} - '@alloy-js/typescript@0.21.0': - resolution: {integrity: sha512-SsxdYkXhrP8jjO2gENav9bHPHaonNrreW469RaOot3cRqhsHPA1RmBrzNPJov37YknzTg4Wlk0JsEFT4Qibgfg==} + '@alloy-js/typescript@0.22.0': + resolution: {integrity: sha512-jARBNxAA5aEhysleFFd7cGfjckkEXLCH9kDaJSH5xBOu4cU0v7q5TvAqgPlEIkhfOh2983XLX0nVtZu01p0UjQ==} '@antfu/install-pkg@1.1.0': resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==} @@ -4439,89 +4439,105 @@ packages: resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-arm@1.2.4': resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-ppc64@1.2.4': resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} cpu: [ppc64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-riscv64@1.2.4': resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} cpu: [riscv64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-s390x@1.2.4': resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-x64@1.2.4': resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linuxmusl-arm64@1.2.4': resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-libvips-linuxmusl-x64@1.2.4': resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-linux-arm64@0.34.5': resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-linux-arm@0.34.5': resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-linux-ppc64@0.34.5': resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ppc64] os: [linux] + libc: [glibc] '@img/sharp-linux-riscv64@0.34.5': resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [riscv64] os: [linux] + libc: [glibc] '@img/sharp-linux-s390x@0.34.5': resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-linux-x64@0.34.5': resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-linuxmusl-arm64@0.34.5': resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-linuxmusl-x64@0.34.5': resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-wasm32@0.34.5': resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} @@ -5554,24 +5570,28 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@reflink/reflink-linux-arm64-musl@0.1.19': resolution: {integrity: sha512-37iO/Dp6m5DDaC2sf3zPtx/hl9FV3Xze4xoYidrxxS9bgP3S8ALroxRK6xBG/1TtfXKTvolvp+IjrUU6ujIGmA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@reflink/reflink-linux-x64-gnu@0.1.19': resolution: {integrity: sha512-jbI8jvuYCaA3MVUdu8vLoLAFqC+iNMpiSuLbxlAgg7x3K5bsS8nOpTRnkLF7vISJ+rVR8W+7ThXlXlUQ93ulkw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@reflink/reflink-linux-x64-musl@0.1.19': resolution: {integrity: sha512-e9FBWDe+lv7QKAwtKOt6A2W/fyy/aEEfr0g6j/hWzvQcrzHCsz07BNQYlNOjTfeytrtLU7k449H1PI95jA4OjQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@reflink/reflink-win32-arm64-msvc@0.1.19': resolution: {integrity: sha512-09PxnVIQcd+UOn4WAW73WU6PXL7DwGS6wPlkMhMg2zlHHG65F3vHepOw06HFCq+N42qkaNAc8AKIabWvtk6cIQ==} @@ -5664,61 +5684,73 @@ packages: resolution: {integrity: sha512-OVSQgEZDVLnTbMq5NBs6xkmz3AADByCWI4RdKSFNlDsYXdFtlxS59J+w+LippJe8KcmeSSM3ba+GlsM9+WwC1w==} cpu: [arm] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.49.0': resolution: {integrity: sha512-ZnfSFA7fDUHNa4P3VwAcfaBLakCbYaxCk0jUnS3dTou9P95kwoOLAMlT3WmEJDBCSrOEFFV0Y1HXiwfLYJuLlA==} cpu: [arm] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.49.0': resolution: {integrity: sha512-Z81u+gfrobVK2iV7GqZCBfEB1y6+I61AH466lNK+xy1jfqFLiQ9Qv716WUM5fxFrYxwC7ziVdZRU9qvGHkYIJg==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.49.0': resolution: {integrity: sha512-zoAwS0KCXSnTp9NH/h9aamBAIve0DXeYpll85shf9NJ0URjSTzzS+Z9evmolN+ICfD3v8skKUPyk2PO0uGdFqg==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-loongarch64-gnu@4.49.0': resolution: {integrity: sha512-2QyUyQQ1ZtwZGiq0nvODL+vLJBtciItC3/5cYN8ncDQcv5avrt2MbKt1XU/vFAJlLta5KujqyHdYtdag4YEjYQ==} cpu: [loong64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-ppc64-gnu@4.49.0': resolution: {integrity: sha512-k9aEmOWt+mrMuD3skjVJSSxHckJp+SiFzFG+v8JLXbc/xi9hv2icSkR3U7uQzqy+/QbbYY7iNB9eDTwrELo14g==} cpu: [ppc64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.49.0': resolution: {integrity: sha512-rDKRFFIWJ/zJn6uk2IdYLc09Z7zkE5IFIOWqpuU0o6ZpHcdniAyWkwSUWE/Z25N/wNDmFHHMzin84qW7Wzkjsw==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-musl@4.49.0': resolution: {integrity: sha512-FkkhIY/hYFVnOzz1WeV3S9Bd1h0hda/gRqvZCMpHWDHdiIHn6pqsY3b5eSbvGccWHMQ1uUzgZTKS4oGpykf8Tw==} cpu: [riscv64] os: [linux] + libc: [musl] '@rollup/rollup-linux-s390x-gnu@4.49.0': resolution: {integrity: sha512-gRf5c+A7QiOG3UwLyOOtyJMD31JJhMjBvpfhAitPAoqZFcOeK3Kc1Veg1z/trmt+2P6F/biT02fU19GGTS529A==} cpu: [s390x] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.40.0': resolution: {integrity: sha512-RcDGMtqF9EFN8i2RYN2W+64CdHruJ5rPqrlYw+cgM3uOVPSsnAQps7cpjXe9be/yDp8UC7VLoCoKC8J3Kn2FkQ==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.49.0': resolution: {integrity: sha512-BR7+blScdLW1h/2hB/2oXM+dhTmpW3rQt1DeSiCP9mc2NMMkqVgjIN3DDsNpKmezffGC9R8XKVOLmBkRUcK/sA==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-musl@4.49.0': resolution: {integrity: sha512-hDMOAe+6nX3V5ei1I7Au3wcr9h3ktKzDvF2ne5ovX8RZiAHEtX1A5SNNk4zt1Qt77CmnbqT+upb/umzoPMWiPg==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-win32-arm64-msvc@4.49.0': resolution: {integrity: sha512-wkNRzfiIGaElC9kXUT+HLx17z7D0jl+9tGYRKwd8r7cUqTL7GYAvgUY++U2hK6Ar7z5Z6IRRoWC8kQxpmM7TDA==} @@ -13710,7 +13742,7 @@ snapshots: - '@babel/core' - supports-color - '@alloy-js/cli@0.21.0': + '@alloy-js/cli@0.22.0': dependencies: '@alloy-js/babel-preset': 0.2.1(@babel/core@7.28.5) '@babel/core': 7.28.5 @@ -13720,7 +13752,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@alloy-js/core@0.21.0': + '@alloy-js/core@0.22.0': dependencies: '@vue/reactivity': 3.5.24 cli-table3: 0.6.5 @@ -13728,22 +13760,22 @@ snapshots: picocolors: 1.1.1 prettier: 3.6.2 - '@alloy-js/csharp@0.21.0': + '@alloy-js/csharp@0.22.0': dependencies: - '@alloy-js/core': 0.21.0 - '@alloy-js/msbuild': 0.21.0 + '@alloy-js/core': 0.22.0 + '@alloy-js/msbuild': 0.22.0 change-case: 5.4.4 marked: 16.4.2 pathe: 2.0.3 - '@alloy-js/markdown@0.21.0': + '@alloy-js/markdown@0.22.0': dependencies: - '@alloy-js/core': 0.21.0 + '@alloy-js/core': 0.22.0 yaml: 2.8.1 - '@alloy-js/msbuild@0.21.0': + '@alloy-js/msbuild@0.22.0': dependencies: - '@alloy-js/core': 0.21.0 + '@alloy-js/core': 0.22.0 change-case: 5.4.4 marked: 16.4.2 pathe: 2.0.3 @@ -13759,9 +13791,9 @@ snapshots: - rollup - supports-color - '@alloy-js/typescript@0.21.0': + '@alloy-js/typescript@0.22.0': dependencies: - '@alloy-js/core': 0.21.0 + '@alloy-js/core': 0.22.0 change-case: 5.4.4 pathe: 2.0.3 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index e50b318c16e..e161307424c 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -12,3 +12,5 @@ overrides: # Minimum age (in minutes) for a new dependency version to be able to be used. minimumReleaseAge: 2880 # 2 days +minimumReleaseAgeExclude: + - "@alloy-js/*" From a2c19395b52c1360938e65f6251a3ce08478e52f Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Mon, 15 Dec 2025 11:09:30 +0800 Subject: [PATCH 36/40] [python] release new version (#9204) --- .../changes/python-array-encode-2025-11-5-10-12-9.md | 7 ------- .../python-fix-docstring-2025-11-10-10-23-28.md | 7 ------- packages/http-client-python/CHANGELOG.md | 11 +++++++++++ packages/http-client-python/package-lock.json | 4 ++-- packages/http-client-python/package.json | 2 +- 5 files changed, 14 insertions(+), 17 deletions(-) delete mode 100644 .chronus/changes/python-array-encode-2025-11-5-10-12-9.md delete mode 100644 .chronus/changes/python-fix-docstring-2025-11-10-10-23-28.md diff --git a/.chronus/changes/python-array-encode-2025-11-5-10-12-9.md b/.chronus/changes/python-array-encode-2025-11-5-10-12-9.md deleted file mode 100644 index af788a49a8f..00000000000 --- a/.chronus/changes/python-array-encode-2025-11-5-10-12-9.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -changeKind: feature -packages: - - "@typespec/http-client-python" ---- - -Support encode for array of string in serialization and deserialization \ No newline at end of file diff --git a/.chronus/changes/python-fix-docstring-2025-11-10-10-23-28.md b/.chronus/changes/python-fix-docstring-2025-11-10-10-23-28.md deleted file mode 100644 index 6abfef34bc4..00000000000 --- a/.chronus/changes/python-fix-docstring-2025-11-10-10-23-28.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -changeKind: fix -packages: - - "@typespec/http-client-python" ---- - -Fix bad indent \ No newline at end of file diff --git a/packages/http-client-python/CHANGELOG.md b/packages/http-client-python/CHANGELOG.md index 76dbabc0395..4a5fa20e0cf 100644 --- a/packages/http-client-python/CHANGELOG.md +++ b/packages/http-client-python/CHANGELOG.md @@ -1,5 +1,16 @@ # Change Log - @typespec/http-client-python +## 0.23.0 + +### Features + +- [#9146](https://github.com/microsoft/typespec/pull/9146) Support encode for array of string in serialization and deserialization + +### Bug Fixes + +- [#8927](https://github.com/microsoft/typespec/pull/8927) Fix bad indent + + ## 0.22.0 ### Features diff --git a/packages/http-client-python/package-lock.json b/packages/http-client-python/package-lock.json index b68d22b8201..5cf53c8046e 100644 --- a/packages/http-client-python/package-lock.json +++ b/packages/http-client-python/package-lock.json @@ -1,12 +1,12 @@ { "name": "@typespec/http-client-python", - "version": "0.22.0", + "version": "0.23.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@typespec/http-client-python", - "version": "0.22.0", + "version": "0.23.0", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/packages/http-client-python/package.json b/packages/http-client-python/package.json index e0b07cff644..9da9830c39c 100644 --- a/packages/http-client-python/package.json +++ b/packages/http-client-python/package.json @@ -1,6 +1,6 @@ { "name": "@typespec/http-client-python", - "version": "0.22.0", + "version": "0.23.0", "author": "Microsoft Corporation", "description": "TypeSpec emitter for Python SDKs", "homepage": "https://typespec.io", From 00c7c678ad13ee617ad5ac2515877df3a56f8761 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Mon, 15 Dec 2025 15:37:45 -0500 Subject: [PATCH 37/40] Backmerge/release/dec 2025 2025 12 15 (#9214) --- packages/compiler/CHANGELOG.md | 7 +++++++ packages/compiler/package.json | 2 +- packages/compiler/src/init/prompts.ts | 7 ++++--- packages/compiler/templates/scaffolding.json | 6 +++--- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/packages/compiler/CHANGELOG.md b/packages/compiler/CHANGELOG.md index d06d3d54bba..2b55e46d03d 100644 --- a/packages/compiler/CHANGELOG.md +++ b/packages/compiler/CHANGELOG.md @@ -1,5 +1,12 @@ # Change Log - @typespec/compiler +## 1.7.1 + +### Bug Fixes + +- [#9210](https://github.com/microsoft/typespec/pull/9210) Fix crash in `tsp init` introduced in `1.7.0` + + ## 1.7.0 ### Features diff --git a/packages/compiler/package.json b/packages/compiler/package.json index 3932fffaef3..a336aa71158 100644 --- a/packages/compiler/package.json +++ b/packages/compiler/package.json @@ -1,6 +1,6 @@ { "name": "@typespec/compiler", - "version": "1.7.0", + "version": "1.7.1", "description": "TypeSpec Compiler Preview", "author": "Microsoft Corporation", "license": "MIT", diff --git a/packages/compiler/src/init/prompts.ts b/packages/compiler/src/init/prompts.ts index 17dd6da1098..1c3983fda1a 100644 --- a/packages/compiler/src/init/prompts.ts +++ b/packages/compiler/src/init/prompts.ts @@ -7,9 +7,10 @@ export function checkbox(config: Parameters + pc.gray( + ` (Press ${pc.cyan("space")} to select, ${pc.cyan("a")} to toggle all, ${pc.cyan("i")} to invert selection and ${pc.cyan("enter")} to proceed.)`, + ), }, icon: { unchecked: pc.cyan(" ◯"), diff --git a/packages/compiler/templates/scaffolding.json b/packages/compiler/templates/scaffolding.json index 66b69f96d69..21a62d71428 100644 --- a/packages/compiler/templates/scaffolding.json +++ b/packages/compiler/templates/scaffolding.json @@ -2,7 +2,7 @@ "rest": { "title": "Generic REST API", "description": "Create a project representing a generic REST API service.", - "compilerVersion": "1.7.0", + "compilerVersion": "1.7.1", "libraries": [ "@typespec/http", "@typespec/rest", @@ -70,7 +70,7 @@ "target": "library", "title": "TypeSpec library", "description": "Build your own TypeSpec library with custom types, decorators or linters.", - "compilerVersion": "1.7.0", + "compilerVersion": "1.7.1", "libraries": [], "files": [ { @@ -147,7 +147,7 @@ "target": "library", "title": "TypeSpec emitter", "description": "Create a new package that emits artifacts from TypeSpec.", - "compilerVersion": "1.7.0", + "compilerVersion": "1.7.1", "libraries": [], "files": [ { From 91cb685480864c699edf191d8167f705c74cc9ea Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Mon, 15 Dec 2025 15:38:26 -0500 Subject: [PATCH 38/40] Fix website accesibility issues (#9175) fix #8556 (Search pane outline) fix #8722 (Links not underlined) fix #8557 (Learn more links) fix #8598 (Terminal/ide image issue) fix #8597 (Hide menu items in docs) fix #8556 (Keyboard focus order in hamburget menu) image --------- Co-authored-by: Mark Cowlishaw <1054056+markcowl@users.noreply.github.com> --- packages/astro-utils/package.json | 6 +- pnpm-lock.yaml | 73 ++++++++++--------- website/astro.config.mjs | 12 +++ website/package.json | 10 +-- website/src/components/asset-img.astro | 5 +- website/src/components/feature-list.astro | 5 +- website/src/components/header/header.astro | 68 ++++++++++++----- website/src/components/header/search.astro | 4 + .../homepage/overview-illustration.astro | 10 ++- website/src/components/learn-more-card.astro | 22 ++++-- website/src/components/light-dark-img.astro | 4 +- .../starlight-overrides/Header.astro | 2 +- website/src/css/reset.css | 5 ++ website/src/pages/index.astro | 3 + 14 files changed, 150 insertions(+), 79 deletions(-) diff --git a/packages/astro-utils/package.json b/packages/astro-utils/package.json index 8a7b2ed075a..4984ea66775 100644 --- a/packages/astro-utils/package.json +++ b/packages/astro-utils/package.json @@ -24,14 +24,14 @@ }, "devDependencies": { "@types/react": "~19.2.2", - "astro": "^5.5.6" + "astro": "^5.16.4" }, "peerDependencies": { - "astro": "^5.5.6" + "astro": "^5.16.4" }, "dependencies": { "@astrojs/check": "^0.9.4", - "@astrojs/starlight": "^0.36.1", + "@astrojs/starlight": "^0.37.0", "@expressive-code/core": "^0.41.2", "@typespec/playground": "workspace:^", "astro-expressive-code": "^0.41.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 998b41bd937..6670a369e4b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -147,8 +147,8 @@ importers: specifier: ^0.9.4 version: 0.9.5(prettier-plugin-astro@0.14.1)(prettier@3.6.2)(typescript@5.9.3) '@astrojs/starlight': - specifier: ^0.36.1 - version: 0.36.2(astro@5.16.0(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1)(@types/node@24.10.1)(rollup@4.49.0)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1)) + specifier: ^0.37.0 + version: 0.37.0(astro@5.16.4(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1)(@types/node@24.10.1)(rollup@4.49.0)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1)) '@expressive-code/core': specifier: ^0.41.2 version: 0.41.3 @@ -157,7 +157,7 @@ importers: version: link:../playground astro-expressive-code: specifier: ^0.41.2 - version: 0.41.3(astro@5.16.0(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1)(@types/node@24.10.1)(rollup@4.49.0)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1)) + version: 0.41.3(astro@5.16.4(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1)(@types/node@24.10.1)(rollup@4.49.0)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1)) pathe: specifier: ^2.0.3 version: 2.0.3 @@ -172,8 +172,8 @@ importers: specifier: ~19.2.2 version: 19.2.6 astro: - specifier: ^5.5.6 - version: 5.16.0(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1)(@types/node@24.10.1)(rollup@4.49.0)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1) + specifier: ^5.16.4 + version: 5.16.4(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1)(@types/node@24.10.1)(rollup@4.49.0)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1) packages/best-practices: devDependencies: @@ -2507,16 +2507,16 @@ importers: specifier: ^0.9.4 version: 0.9.5(prettier-plugin-astro@0.14.1)(prettier@3.6.2)(typescript@5.9.3) '@astrojs/react': - specifier: ^4.2.1 + specifier: ^4.4.2 version: 4.4.2(@types/node@24.10.1)(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(tsx@4.20.6)(yaml@2.8.1) '@astrojs/starlight': - specifier: ^0.36.1 - version: 0.36.2(astro@5.16.0(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1)(@types/node@24.10.1)(rollup@4.49.0)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1)) + specifier: ^0.37.0 + version: 0.37.0(astro@5.16.4(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1)(@types/node@24.10.1)(rollup@4.49.0)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1)) '@docsearch/css': - specifier: ^4.1.0 + specifier: ^4.3.2 version: 4.3.2 '@docsearch/js': - specifier: ^4.1.0 + specifier: ^4.3.2 version: 4.3.2 '@expressive-code/core': specifier: ^0.41.2 @@ -2534,11 +2534,11 @@ importers: specifier: workspace:^ version: link:../packages/playground astro: - specifier: ^5.5.6 - version: 5.16.0(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1)(@types/node@24.10.1)(rollup@4.49.0)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1) + specifier: ^5.16.4 + version: 5.16.4(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1)(@types/node@24.10.1)(rollup@4.49.0)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1) astro-rehype-relative-markdown-links: specifier: ^0.18.1 - version: 0.18.1(astro@5.16.0(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1)(@types/node@24.10.1)(rollup@4.49.0)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1)) + version: 0.18.1(astro@5.16.4(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1)(@types/node@24.10.1)(rollup@4.49.0)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1)) clsx: specifier: ^2.1.1 version: 2.1.1 @@ -2635,7 +2635,7 @@ importers: version: link:../packages/xml astro-expressive-code: specifier: ^0.41.2 - version: 0.41.3(astro@5.16.0(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1)(@types/node@24.10.1)(rollup@4.49.0)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1)) + version: 0.41.3(astro@5.16.4(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1)(@types/node@24.10.1)(rollup@4.49.0)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1)) rehype-mermaid: specifier: ^3.0.0 version: 3.0.0(playwright@1.56.1) @@ -2797,8 +2797,8 @@ packages: '@astrojs/sitemap@3.6.0': resolution: {integrity: sha512-4aHkvcOZBWJigRmMIAJwRQXBS+ayoP5z40OklTXYXhUDhwusz+DyDl+nSshY6y9DvkVEavwNcFO8FD81iGhXjg==} - '@astrojs/starlight@0.36.2': - resolution: {integrity: sha512-QR8NfO7+7DR13kBikhQwAj3IAoptLLNs9DkyKko2M2l3PrqpcpVUnw1JBJ0msGDIwE6tBbua2UeBND48mkh03w==} + '@astrojs/starlight@0.37.0': + resolution: {integrity: sha512-1AlaEjYYRO+5o6P5maPUBQZr6Q3wtuhMQTmsDQExI07wJVwe7EC2wGhXnFo+jpCjwHv/Bdg33PQheY4UhMj01g==} peerDependencies: astro: ^5.5.0 @@ -7210,8 +7210,8 @@ packages: peerDependencies: astro: '>=2 <6' - astro@5.16.0: - resolution: {integrity: sha512-GaDRs2Mngpw3dr2vc085GnORh98NiXxwIjg/EoQQQl/icZt3Z7s0BRsYHDZ8swkZbOA6wZsqWJdrNirl+iKcDg==} + astro@5.16.4: + resolution: {integrity: sha512-rgXI/8/tnO3Y9tfAaUyg/8beKhlIMltbiC8Q6jCoAfEidOyaue4KYKzbe0gJIb6qEdEaG3Kf3BY3EOSLkbWOLg==} engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0'} hasBin: true @@ -12886,8 +12886,8 @@ packages: resolution: {integrity: sha512-6NCPkv1ClwH+/BGE9QeoTIl09nuiAt0gS28nn1PvYXsGKRwM2TCbFA2QiilmehPDTXIe684k4rZI1yl3A1PCUw==} engines: {node: '>=18.12.0'} - unstorage@1.17.2: - resolution: {integrity: sha512-cKEsD6iBWJgOMJ6vW1ID/SYuqNf8oN4yqRk8OYqaVQ3nnkJXOT1PSpaMh2QfzLs78UN5kSNRD2c/mgjT8tX7+w==} + unstorage@1.17.3: + resolution: {integrity: sha512-i+JYyy0DoKmQ3FximTHbGadmIYb8JEpq7lxUjnjeB702bCPum0vzo6oy5Mfu0lpqISw7hCyMW2yj4nWC8bqJ3Q==} peerDependencies: '@azure/app-configuration': ^1.8.0 '@azure/cosmos': ^4.2.0 @@ -13883,12 +13883,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@astrojs/mdx@4.3.12(astro@5.16.0(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1)(@types/node@24.10.1)(rollup@4.49.0)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1))': + '@astrojs/mdx@4.3.12(astro@5.16.4(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1)(@types/node@24.10.1)(rollup@4.49.0)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1))': dependencies: '@astrojs/markdown-remark': 6.3.9 '@mdx-js/mdx': 3.1.1 acorn: 8.15.0 - astro: 5.16.0(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1)(@types/node@24.10.1)(rollup@4.49.0)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1) + astro: 5.16.4(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1)(@types/node@24.10.1)(rollup@4.49.0)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1) es-module-lexer: 1.7.0 estree-util-visit: 2.0.0 hast-util-to-html: 9.0.5 @@ -13935,17 +13935,17 @@ snapshots: stream-replace-string: 2.0.0 zod: 3.25.76 - '@astrojs/starlight@0.36.2(astro@5.16.0(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1)(@types/node@24.10.1)(rollup@4.49.0)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1))': + '@astrojs/starlight@0.37.0(astro@5.16.4(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1)(@types/node@24.10.1)(rollup@4.49.0)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1))': dependencies: '@astrojs/markdown-remark': 6.3.9 - '@astrojs/mdx': 4.3.12(astro@5.16.0(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1)(@types/node@24.10.1)(rollup@4.49.0)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1)) + '@astrojs/mdx': 4.3.12(astro@5.16.4(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1)(@types/node@24.10.1)(rollup@4.49.0)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1)) '@astrojs/sitemap': 3.6.0 '@pagefind/default-ui': 1.4.0 '@types/hast': 3.0.4 '@types/js-yaml': 4.0.9 '@types/mdast': 4.0.4 - astro: 5.16.0(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1)(@types/node@24.10.1)(rollup@4.49.0)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1) - astro-expressive-code: 0.41.3(astro@5.16.0(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1)(@types/node@24.10.1)(rollup@4.49.0)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1)) + astro: 5.16.4(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1)(@types/node@24.10.1)(rollup@4.49.0)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1) + astro-expressive-code: 0.41.3(astro@5.16.4(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1)(@types/node@24.10.1)(rollup@4.49.0)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1)) bcp-47: 2.1.0 hast-util-from-html: 2.0.3 hast-util-select: 6.0.4 @@ -13954,6 +13954,7 @@ snapshots: i18next: 23.16.8 js-yaml: 4.1.1 klona: 2.0.6 + magic-string: 0.30.21 mdast-util-directive: 3.1.0 mdast-util-to-markdown: 2.1.2 mdast-util-to-string: 4.0.0 @@ -18851,7 +18852,7 @@ snapshots: '@types/sax@1.2.7': dependencies: - '@types/node': 17.0.45 + '@types/node': 24.10.1 '@types/semver@7.7.1': {} @@ -19584,7 +19585,7 @@ snapshots: algoliasearch: 4.25.3 clipanion: 4.0.0-rc.4(typanion@3.14.0) diff: 5.2.0 - ink: 3.2.0(@types/react@19.2.6)(react@17.0.2) + ink: 3.2.0(@types/react@19.2.6)(react@18.3.1) ink-text-input: 4.0.3(ink@3.2.0(@types/react@19.2.6)(react@17.0.2))(react@17.0.2) react: 17.0.2 semver: 7.7.3 @@ -19734,7 +19735,7 @@ snapshots: '@yarnpkg/plugin-git': 3.1.3(@yarnpkg/core@4.5.0(typanion@3.14.0))(typanion@3.14.0) clipanion: 4.0.0-rc.4(typanion@3.14.0) es-toolkit: 1.42.0 - ink: 3.2.0(@types/react@19.2.6)(react@18.3.1) + ink: 3.2.0(@types/react@19.2.6)(react@17.0.2) react: 17.0.2 semver: 7.7.3 tslib: 2.8.1 @@ -20084,14 +20085,14 @@ snapshots: astring@1.9.0: {} - astro-expressive-code@0.41.3(astro@5.16.0(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1)(@types/node@24.10.1)(rollup@4.49.0)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1)): + astro-expressive-code@0.41.3(astro@5.16.4(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1)(@types/node@24.10.1)(rollup@4.49.0)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1)): dependencies: - astro: 5.16.0(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1)(@types/node@24.10.1)(rollup@4.49.0)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1) + astro: 5.16.4(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1)(@types/node@24.10.1)(rollup@4.49.0)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1) rehype-expressive-code: 0.41.3 - astro-rehype-relative-markdown-links@0.18.1(astro@5.16.0(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1)(@types/node@24.10.1)(rollup@4.49.0)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1)): + astro-rehype-relative-markdown-links@0.18.1(astro@5.16.4(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1)(@types/node@24.10.1)(rollup@4.49.0)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1)): dependencies: - astro: 5.16.0(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1)(@types/node@24.10.1)(rollup@4.49.0)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1) + astro: 5.16.4(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1)(@types/node@24.10.1)(rollup@4.49.0)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1) catch-unknown: 2.0.0 debug: 4.4.3(supports-color@8.1.1) github-slugger: 2.0.0 @@ -20103,7 +20104,7 @@ snapshots: transitivePeerDependencies: - supports-color - astro@5.16.0(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1)(@types/node@24.10.1)(rollup@4.49.0)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1): + astro@5.16.4(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1)(@types/node@24.10.1)(rollup@4.49.0)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1): dependencies: '@astrojs/compiler': 2.13.0 '@astrojs/internal-helpers': 0.7.5 @@ -20158,7 +20159,7 @@ snapshots: ultrahtml: 1.6.0 unifont: 0.6.0 unist-util-visit: 5.0.0 - unstorage: 1.17.2(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1) + unstorage: 1.17.3(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1) vfile: 6.0.3 vite: 6.4.1(@types/node@24.10.1)(tsx@4.20.6)(yaml@2.8.1) vitefu: 1.1.1(vite@6.4.1(@types/node@24.10.1)(tsx@4.20.6)(yaml@2.8.1)) @@ -27226,7 +27227,7 @@ snapshots: picomatch: 4.0.3 webpack-virtual-modules: 0.6.2 - unstorage@1.17.2(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1): + unstorage@1.17.3(@azure/identity@4.13.0)(@azure/storage-blob@12.29.1): dependencies: anymatch: 3.1.3 chokidar: 4.0.3 diff --git a/website/astro.config.mjs b/website/astro.config.mjs index a691c046022..8bb1ec30150 100644 --- a/website/astro.config.mjs +++ b/website/astro.config.mjs @@ -51,6 +51,18 @@ export default defineConfig({ }, }, ], + social: [ + { + label: "GitHub", + icon: "github", + href: "https://github.com/microsoft/typespec", + }, + { + label: "Discord", + icon: "discord", + href: "https://aka.ms/typespec/discord", + }, + ], plugins: [], }), react(), diff --git a/website/package.json b/website/package.json index 90924191924..28784387449 100644 --- a/website/package.json +++ b/website/package.json @@ -17,16 +17,16 @@ }, "dependencies": { "@astrojs/check": "^0.9.4", - "@astrojs/react": "^4.2.1", - "@astrojs/starlight": "^0.36.1", - "@docsearch/css": "^4.1.0", - "@docsearch/js": "^4.1.0", + "@astrojs/react": "^4.4.2", + "@astrojs/starlight": "^0.37.0", + "@docsearch/css": "^4.3.2", + "@docsearch/js": "^4.3.2", "@expressive-code/core": "^0.41.2", "@fluentui/react-components": "~9.72.3", "@fluentui/react-icons": "^2.0.292", "@typespec/compiler": "workspace:^", "@typespec/playground": "workspace:^", - "astro": "^5.5.6", + "astro": "^5.16.4", "astro-rehype-relative-markdown-links": "^0.18.1", "clsx": "^2.1.1", "date-fns": "^4.1.0", diff --git a/website/src/components/asset-img.astro b/website/src/components/asset-img.astro index f264835ec2f..456b3b6f9ec 100644 --- a/website/src/components/asset-img.astro +++ b/website/src/components/asset-img.astro @@ -7,12 +7,13 @@ import type { HTMLAttributes } from "astro/types"; export interface AssetImgProps extends HTMLAttributes<"img"> { src: string; + class?: string; } -const { src, alt, ...rest } = Astro.props; +const { src, alt, class: className, ...rest } = Astro.props; --- -{alt +{alt diff --git a/website/src/components/homepage/overview-illustration.astro b/website/src/components/homepage/overview-illustration.astro index a7db55bebbf..25f770c0365 100644 --- a/website/src/components/homepage/overview-illustration.astro +++ b/website/src/components/homepage/overview-illustration.astro @@ -8,8 +8,8 @@ import { OverviewIllustrationTerminalContent } from "./overview-illustration-ter diff --git a/website/src/components/learn-more-card.astro b/website/src/components/learn-more-card.astro index 6e9ce657bea..745aac57a4f 100644 --- a/website/src/components/learn-more-card.astro +++ b/website/src/components/learn-more-card.astro @@ -1,7 +1,7 @@ --- import FluentImg from "./fluent-img.astro"; import Link from "@typespec/astro-utils/components/link.astro"; -import { NeutralText, DescriptionText, Text } from "./text/text"; +import { NeutralText, DescriptionText } from "./text/text"; import type { FluentImageName } from "./types"; export interface Props { @@ -24,6 +24,7 @@ const { image, title, description, link } = Astro.props; display: flex; gap: 12px; border: 2px solid transparent; + display: flex; } .item:hover { @@ -44,16 +45,25 @@ const { image, title, description, link } = Astro.props; .item-content { display: flex; + flex: 1; flex-direction: column; - gap: 12px; + } + + .title { + font-size: 20px; + font-weight: 600; + } + .arrow { + font-size: 24px; + color: var(--colorNeutralForeground3); } {image && } -
- {title} - {description} - Learn more → +
+ {title} + {description ?? "Learn more about supported features"}
+
→
diff --git a/website/src/components/light-dark-img.astro b/website/src/components/light-dark-img.astro index 8f37b1231b0..5864839305b 100644 --- a/website/src/components/light-dark-img.astro +++ b/website/src/components/light-dark-img.astro @@ -23,6 +23,6 @@ const { src } = Astro.props; }
- - + +
diff --git a/website/src/components/starlight-overrides/Header.astro b/website/src/components/starlight-overrides/Header.astro index abb7f4cd7e4..4d838b63f08 100644 --- a/website/src/components/starlight-overrides/Header.astro +++ b/website/src/components/starlight-overrides/Header.astro @@ -2,4 +2,4 @@ import BaseHeader from "@site/src/components/header/header.astro"; --- - + diff --git a/website/src/css/reset.css b/website/src/css/reset.css index a7fdd011b58..475426647cb 100644 --- a/website/src/css/reset.css +++ b/website/src/css/reset.css @@ -13,3 +13,8 @@ a { text-decoration: none; transition: color var(--ifm-transition-fast) var(--ifm-transition-timing-default); } + +/* In markdown tables starlight doesn't underline text. This ensures that only links with multiple siblings get underlined but not the whole cell being a link */ +.sl-markdown-content td a:not(:only-child) { + text-decoration: underline; +} diff --git a/website/src/pages/index.astro b/website/src/pages/index.astro index 3b4a8568a9f..f60918dc85b 100644 --- a/website/src/pages/index.astro +++ b/website/src/pages/index.astro @@ -113,12 +113,14 @@ import Button from "../components/button.astro"; "Inspired by TypeScript, TypeSpec is a minimal language that helps developers describe API shapes in a familiar way.", image: "book-pencil", link: Links.gettingStartedOpenAPI, + learnMoreText: "Learn about TypeSpec for REST APIs", }, { title: "Easy integration with your toolchain", description: "Write TypeSpec, emit to various formats and integrate with their ecosystems.", image: "document-add", + learnMoreText: "Learn about TypeSpec emitters", }, { title: "Multi-protocol support", @@ -126,6 +128,7 @@ import Button from "../components/button.astro"; "TypeSpec's standard library includes support for OpenAPI 3.0, JSON Schema 2020-12 and Protobuf.", image: "tasks", link: "/multi-protocol", + learnMoreText: "Check out multi-protocol examples", }, ]} /> From d7f969b6e6a39fe40d9e9b0ff054f601f44b92f9 Mon Sep 17 00:00:00 2001 From: Brian Terlson Date: Mon, 15 Dec 2025 15:45:36 -0800 Subject: [PATCH 39/40] Mutator and HTTP Canonicalization updates (#9141) Having used these tools for a reasonably complete REST emitter, the following fixes and improvements have been implemented: ## Mutator framework ### General * Fix mutations not handling linkage to parent types (e.g. model property -> model). * Remove mutation subgraph, nodes are now unique per (type, key) pair. * Remove reference mutations, use a distinct key for references if needed. * Added various `SimpleMutation`s and `SimpleMutationEngine` for doing mutations of the graph where only one mutated type is needed per source type. ### Mutation Nodes * Connections are now built lazily. Nodes get a `startXEdge` method which returns a `HalfEdge` that can be connected to the mutation node for that type. This is necessary because we can't know what node we're going to connect to in advance (since it depends on the eventual `mutationKey` we'll calculate for it, see below). The only exception to this is when connecting to member types which refer back to the member container - connecting the container to a member will connect the member to the container. ### Mutations * Mutations are now abstract classes. * Mutations have a new protocol - a static method `mutationInfo` is called which returns a unique `mutationKey` for that mutation (along with other information if needed). If the `mutationKey` has been seen before, the previous one is returned. Otherwise, the appropriate `Mutation` is constructed passing along the mutationInfo. * `mutationInfo` can also return a `Mutation`, in which case it is used directly. Useful for constructing a Mutation view "as if" the type graph looked a different way. * Mutations have methods to create `MutationHalfEdge` types for connected type which can be passed along to the engine's `mutate` method. When we figure out what `Mutation` to use based on the `mutationKey` we calculate, it is connected by calling `setTail`. ## HTTP Canonicalization ### General * Fix canonicalization of merge patch models. * Remove metadata properties from wire types. * Added a new method `subgraphMatchesPredicate` to `HttpCanonicalizer` and `HttpCanonicalization` classes. This is a cycle safe way to see if the subgraph rooted at a particular canonicalization all have a certain property. * Various fixes and improvements to union variant discrimination tests * Normalize @discriminator models on base type to a union of their subtypes when appropriate. * Add support for "extensible union" pattern * Add support for requests/responses multiple content types * Apply getEffectiveModel to all models. ### Codecs * Codecs have a new protocol - the `detect` method has been removed, codec instances have `encode` which either returns `null` or `EncodingInfo` if it encodes the given type. * Codecs now operate on types rather than http canonicalizations (making them more general purpose) * Codecs can be configured by constructing them with various options. CoerceToFloat64 codec has options for whether to encode int64,decimal, etc. * Added a Rename codec to rename the language type for types which have friendlyName, or have language-specific case conventions that differ from the API. ## Emitter framework * Add an SCCSet class which incrementally calculates strongly connected components from types added to it and updates reactive arrays with the topologically ordered types and components. --- .../changes/ef-updates-2025-11-4-17-44-46.md | 8 + .../changes/ef-updates-2025-11-4-17-45-6.md | 7 + .../changes/updates-2025-10-11-11-38-50.md | 7 + .../changes/updates-2025-10-11-11-39-17.md | 7 + .../changes/updates-2025-10-11-11-39-37.md | 7 + packages/emitter-framework/src/core/index.ts | 2 + .../src/core/scc-set.test.ts | 293 +++++++ .../emitter-framework/src/core/scc-set.ts | 777 ++++++++++++++++++ .../src/core/type-connector.ts | 67 ++ packages/http-canonicalization/CHANGELOG.md | 3 - packages/http-canonicalization/package.json | 1 + packages/http-canonicalization/src/codecs.ts | 352 ++++---- .../src/enum-member.test.ts | 75 ++ .../http-canonicalization/src/enum-member.ts | 109 +++ .../http-canonicalization/src/enum.test.ts | 148 ++++ packages/http-canonicalization/src/enum.ts | 115 +++ .../src/http-canonicalization-classes.ts | 4 + .../src/http-canonicalization.test.ts | 239 +++++- .../src/http-canonicalization.ts | 378 ++++++++- packages/http-canonicalization/src/index.ts | 2 + .../http-canonicalization/src/intrinsic.ts | 110 ++- packages/http-canonicalization/src/literal.ts | 104 ++- .../src/model-property.test.ts | 134 ++- .../src/model-property.ts | 199 ++++- .../http-canonicalization/src/model.test.ts | 141 ++++ packages/http-canonicalization/src/model.ts | 265 ++++-- .../src/operation.test.ts | 105 ++- .../http-canonicalization/src/operation.ts | 167 +++- packages/http-canonicalization/src/options.ts | 11 +- .../http-canonicalization/src/scalar.test.ts | 59 +- packages/http-canonicalization/src/scalar.ts | 135 ++- .../src/union-variant.ts | 115 ++- .../http-canonicalization/src/union.test.ts | 69 +- packages/http-canonicalization/src/union.ts | 230 ++++-- packages/mutator-framework/readme.md | 437 +++++----- .../src/mutation-node/enum-member.test.ts | 45 +- .../src/mutation-node/enum-member.ts | 23 +- .../src/mutation-node/enum.test.ts | 35 +- .../src/mutation-node/enum.ts | 42 +- .../src/mutation-node/factory.ts | 31 +- .../src/mutation-node/index.ts | 2 +- .../src/mutation-node/interface.ts | 44 +- .../src/mutation-node/intrinsic.ts | 5 +- .../src/mutation-node/literal.ts | 5 +- .../src/mutation-node/model-property.test.ts | 276 ++++--- .../src/mutation-node/model-property.ts | 79 +- .../src/mutation-node/model.test.ts | 95 ++- .../src/mutation-node/model.ts | 159 +++- .../src/mutation-node/mutation-edge.ts | 148 +++- .../src/mutation-node/mutation-node.test.ts | 93 ++- .../src/mutation-node/mutation-node.ts | 127 ++- .../src/mutation-node/mutation-subgraph.ts | 59 -- .../src/mutation-node/operation.ts | 76 +- .../src/mutation-node/scalar.test.ts | 24 +- .../src/mutation-node/scalar.ts | 39 +- .../src/mutation-node/tracer.ts | 18 + .../src/mutation-node/tuple.test.ts | 15 +- .../src/mutation-node/tuple.ts | 39 +- .../src/mutation-node/union-variant.test.ts | 46 +- .../src/mutation-node/union-variant.ts | 51 +- .../src/mutation-node/union.test.ts | 9 +- .../src/mutation-node/union.ts | 42 +- .../src/mutation/enum-member.ts | 5 +- .../mutator-framework/src/mutation/enum.ts | 5 +- .../src/mutation/interface.ts | 17 +- .../src/mutation/intrinsic.ts | 7 +- .../mutator-framework/src/mutation/literal.ts | 7 +- .../src/mutation/model-property.ts | 27 +- .../mutator-framework/src/mutation/model.ts | 54 +- .../src/mutation/mutation-engine.test.ts | 271 ------ .../src/mutation/mutation-engine.ts | 367 +++++---- .../src/mutation/mutation.ts | 92 +-- .../src/mutation/operation.ts | 25 +- .../mutator-framework/src/mutation/scalar.ts | 18 +- .../mutation/simple-mutation-engine.test.ts | 330 ++++++++ .../src/mutation/simple-mutation-engine.ts | 462 ++++++++++- .../src/mutation/union-variant.ts | 14 +- .../mutator-framework/src/mutation/union.ts | 23 +- packages/mutator-framework/test/utils.ts | 7 +- pnpm-lock.yaml | 3 + 80 files changed, 6316 insertions(+), 1927 deletions(-) create mode 100644 .chronus/changes/ef-updates-2025-11-4-17-44-46.md create mode 100644 .chronus/changes/ef-updates-2025-11-4-17-45-6.md create mode 100644 .chronus/changes/updates-2025-10-11-11-38-50.md create mode 100644 .chronus/changes/updates-2025-10-11-11-39-17.md create mode 100644 .chronus/changes/updates-2025-10-11-11-39-37.md create mode 100644 packages/emitter-framework/src/core/scc-set.test.ts create mode 100644 packages/emitter-framework/src/core/scc-set.ts create mode 100644 packages/emitter-framework/src/core/type-connector.ts create mode 100644 packages/http-canonicalization/src/enum-member.test.ts create mode 100644 packages/http-canonicalization/src/enum-member.ts create mode 100644 packages/http-canonicalization/src/enum.test.ts create mode 100644 packages/http-canonicalization/src/enum.ts create mode 100644 packages/http-canonicalization/src/model.test.ts delete mode 100644 packages/mutator-framework/src/mutation-node/mutation-subgraph.ts create mode 100644 packages/mutator-framework/src/mutation-node/tracer.ts delete mode 100644 packages/mutator-framework/src/mutation/mutation-engine.test.ts create mode 100644 packages/mutator-framework/src/mutation/simple-mutation-engine.test.ts diff --git a/.chronus/changes/ef-updates-2025-11-4-17-44-46.md b/.chronus/changes/ef-updates-2025-11-4-17-44-46.md new file mode 100644 index 00000000000..f790d7ec3d8 --- /dev/null +++ b/.chronus/changes/ef-updates-2025-11-4-17-44-46.md @@ -0,0 +1,8 @@ +--- +changeKind: breaking +packages: + - "@typespec/http-canonicalization" + - "@typespec/mutator-framework" +--- + +Many other bug fixes, removals, and additions as described in this pull request: https://github.com/microsoft/typespec/pull/9141 \ No newline at end of file diff --git a/.chronus/changes/ef-updates-2025-11-4-17-45-6.md b/.chronus/changes/ef-updates-2025-11-4-17-45-6.md new file mode 100644 index 00000000000..1a7262852a6 --- /dev/null +++ b/.chronus/changes/ef-updates-2025-11-4-17-45-6.md @@ -0,0 +1,7 @@ +--- +changeKind: feature +packages: + - "@typespec/emitter-framework" +--- + +Add an SCCSet class which incrementally calculates strongly connected components from types added to it and updates reactive arrays with the topologically ordered types and components. \ No newline at end of file diff --git a/.chronus/changes/updates-2025-10-11-11-38-50.md b/.chronus/changes/updates-2025-10-11-11-38-50.md new file mode 100644 index 00000000000..943280b4433 --- /dev/null +++ b/.chronus/changes/updates-2025-10-11-11-38-50.md @@ -0,0 +1,7 @@ +--- +changeKind: breaking +packages: + - "@typespec/mutator-framework" +--- + +Fix mutations not handling linkage to parent types (e.g. model property -> model). Remove mutation subgraph, nodes are now unique per (type, key) pair. Remove reference mutations, use a distinct key for references if needed. \ No newline at end of file diff --git a/.chronus/changes/updates-2025-10-11-11-39-17.md b/.chronus/changes/updates-2025-10-11-11-39-17.md new file mode 100644 index 00000000000..6846af685f1 --- /dev/null +++ b/.chronus/changes/updates-2025-10-11-11-39-17.md @@ -0,0 +1,7 @@ +--- +changeKind: fix +packages: + - "@typespec/http-canonicalization" +--- + +Fix canonicalization of merge patch models. \ No newline at end of file diff --git a/.chronus/changes/updates-2025-10-11-11-39-37.md b/.chronus/changes/updates-2025-10-11-11-39-37.md new file mode 100644 index 00000000000..f1578a2537b --- /dev/null +++ b/.chronus/changes/updates-2025-10-11-11-39-37.md @@ -0,0 +1,7 @@ +--- +changeKind: fix +packages: + - "@typespec/http-canonicalization" +--- + +Remove metadata properties from wire types. \ No newline at end of file diff --git a/packages/emitter-framework/src/core/index.ts b/packages/emitter-framework/src/core/index.ts index 2b854ed8c66..6b3d6fb8a5a 100644 --- a/packages/emitter-framework/src/core/index.ts +++ b/packages/emitter-framework/src/core/index.ts @@ -1,4 +1,6 @@ export * from "./components/index.js"; export * from "./context/index.js"; +export * from "./scc-set.js"; export * from "./transport-name-policy.js"; +export * from "./type-connector.js"; export * from "./write-output.js"; diff --git a/packages/emitter-framework/src/core/scc-set.test.ts b/packages/emitter-framework/src/core/scc-set.test.ts new file mode 100644 index 00000000000..19dbc746eba --- /dev/null +++ b/packages/emitter-framework/src/core/scc-set.test.ts @@ -0,0 +1,293 @@ +import { Tester } from "#test/test-host.js"; +import { computed } from "@alloy-js/core"; +import type { Type } from "@typespec/compiler"; +import { t } from "@typespec/compiler/testing"; +import { describe, expect, it, vi } from "vitest"; +import { SCCSet, type NestedArray, type SCCComponent } from "./scc-set.js"; +import { typeDependencyConnector } from "./type-connector.js"; + +describe("SCCSet", () => { + it("topologically orders items", () => { + const edges = new Map([ + ["model", ["serializer"]], + ["serializer", ["helpers"]], + ["helpers", []], + ]); + + const set = new SCCSet((item) => edges.get(item) ?? []); + set.add("model"); + set.add("serializer"); + set.add("helpers"); + + expect([...set.items]).toEqual(["helpers", "serializer", "model"]); + expect(componentValues(set)).toEqual(["helpers", "serializer", "model"]); + }); + + it("groups strongly connected components", () => { + const edges = new Map([ + ["a", ["b"]], + ["b", ["a", "c"]], + ["c", []], + ]); + + const set = new SCCSet((item) => edges.get(item) ?? []); + set.add("a"); + set.add("b"); + set.add("c"); + + expect(componentValues(set)).toEqual(["c", ["a", "b"]]); + expect(set.items).toEqual(["c", "a", "b"]); + }); + + it("defers placeholders until added", () => { + const edges = new Map([ + ["root", ["child"]], + ["child", []], + ]); + + const set = new SCCSet((item) => edges.get(item) ?? []); + + set.add("root"); + expect(set.items).toEqual(["root"]); + expect(componentValues(set)).toEqual(["root"]); + + set.add("child"); + expect(set.items).toEqual(["child", "root"]); + expect(componentValues(set)).toEqual(["child", "root"]); + }); + + it("surfaces reachable nodes when requested", () => { + const edges = new Map([ + ["root", ["child"]], + ["child", ["leaf"]], + ["leaf", []], + ]); + + const set = new SCCSet((item) => edges.get(item) ?? [], { includeReachable: true }); + set.add("root"); + + expect(set.items).toEqual(["leaf", "child", "root"]); + expect(componentValues(set)).toEqual(["leaf", "child", "root"]); + }); + + it("mutates arrays in place when adding", () => { + const edges = new Map([["only", []]]); + const connector = vi.fn((item: string) => edges.get(item) ?? []); + + const set = new SCCSet(connector); + set.add("only"); + + const firstItems = set.items; + const firstComponents = set.components; + + expect(set.items).toBe(firstItems); + expect(set.components).toBe(firstComponents); + expect(connector).toHaveBeenCalledTimes(1); + + set.add("late"); + expect(connector).toHaveBeenCalledTimes(2); + expect(set.items).toBe(firstItems); + expect(set.components).toBe(firstComponents); + expect(firstItems).toEqual(["only", "late"]); + expect(componentValuesFrom(firstComponents)).toEqual(["only", "late"]); + }); + + it("notifies computed observers", () => { + const edges = new Map([ + ["model", ["serializer"]], + ["serializer", ["helpers"]], + ["helpers", []], + ["cycle-a", ["cycle-b"]], + ["cycle-b", ["cycle-a"]], + ]); + + const set = new SCCSet((item) => edges.get(item) ?? []); + const observedItems = computed(() => [...set.items]); + const observedComponents = computed(() => componentValues(set)); + const observedCycle = computed(() => { + const cycle = set.components.find((component) => Array.isArray(component.value)); + if (!cycle || !Array.isArray(cycle.value)) { + return []; + } + return [...cycle.value]; + }); + + expect(observedItems.value).toEqual([]); + expect(observedComponents.value).toEqual([]); + expect(observedCycle.value).toEqual([]); + + set.add("model"); + expect(observedItems.value).toEqual(["model"]); + expect(observedComponents.value).toEqual(["model"]); + + set.add("serializer"); + expect(observedItems.value).toEqual(["serializer", "model"]); + expect(observedComponents.value).toEqual(["serializer", "model"]); + + set.add("helpers"); + expect(observedItems.value).toEqual(["helpers", "serializer", "model"]); + expect(observedComponents.value).toEqual(["helpers", "serializer", "model"]); + + set.add("cycle-a"); + expect(observedCycle.value).toEqual([]); + + set.add("cycle-b"); + expect(observedCycle.value).toEqual(["cycle-a", "cycle-b"]); + }); + + it("orders dependent nodes even when added out of order", () => { + const edges = new Map([ + ["Leaf", []], + ["Indexed", ["Record"]], + ["Record", ["Leaf"]], + ["Base", ["Leaf"]], + ["Derived", ["Base", "Indexed"]], + ["CycleA", ["CycleB"]], + ["CycleB", ["CycleA"]], + ]); + + const insertionOrder = ["Derived", "Indexed", "Leaf", "Base", "CycleA", "CycleB"]; + const set = new SCCSet((item) => edges.get(item) ?? []); + for (const item of insertionOrder) { + set.add(item); + } + + expect([...set.items]).toEqual(["Leaf", "Indexed", "Base", "Derived", "CycleA", "CycleB"]); + expect(componentValues(set)).toEqual([ + "Leaf", + "Indexed", + "Base", + "Derived", + ["CycleA", "CycleB"], + ]); + }); + + it("batch adds nodes and recomputes once", () => { + const edges = new Map([ + ["Leaf", []], + ["Indexed", ["Record"]], + ["Record", ["Leaf"]], + ["Base", ["Leaf"]], + ["Derived", ["Base", "Indexed"]], + ["CycleA", ["CycleB"]], + ["CycleB", ["CycleA"]], + ]); + + const insertionOrder = ["Derived", "Indexed", "Leaf", "Base", "CycleA", "CycleB"]; + const set = new SCCSet((item) => edges.get(item) ?? []); + set.addAll(insertionOrder); + + expect([...set.items]).toEqual(["Leaf", "Indexed", "Base", "Derived", "CycleA", "CycleB"]); + expect(componentValues(set)).toEqual([ + "Leaf", + "Indexed", + "Base", + "Derived", + ["CycleA", "CycleB"], + ]); + }); + + it("exposes component connections", () => { + const edges = new Map([ + ["Leaf", []], + ["Base", ["Leaf"]], + ["Indexed", ["Leaf"]], + ["Derived", ["Base", "Indexed"]], + ["CycleA", ["CycleB"]], + ["CycleB", ["CycleA"]], + ]); + + const set = new SCCSet((item) => edges.get(item) ?? []); + set.addAll(["Derived", "Base", "Indexed", "Leaf", "CycleA", "CycleB"]); + + const getSingleton = (name: string) => + set.components.find((component) => component.value === name)!; + const format = (components: Iterable>) => + Array.from(components, (component) => + Array.isArray(component.value) ? component.value.join(",") : component.value, + ).sort(); + + const derived = getSingleton("Derived"); + const base = getSingleton("Base"); + const indexed = getSingleton("Indexed"); + const leaf = getSingleton("Leaf"); + const cycle = set.components.find((component) => Array.isArray(component.value))!; + + expect(format(derived.references)).toEqual(["Base", "Indexed"]); + expect(format(base.references)).toEqual(["Leaf"]); + expect(format(base.referencedBy)).toEqual(["Derived"]); + expect(format(indexed.referencedBy)).toEqual(["Derived"]); + expect(format(leaf.referencedBy)).toEqual(["Base", "Indexed"]); + expect(format(cycle.references)).toEqual([]); + expect(format(cycle.referencedBy)).toEqual([]); + }); + + it("orders TypeSpec models via connector", async () => { + const tester = await Tester.createInstance(); + const { Leaf, Indexed, Base, Derived, CycleA, CycleB } = await tester.compile( + t.code` + @test model ${t.model("Leaf")} { + value: string; + } + + @test model ${t.model("Indexed")} extends Record {} + + @test model ${t.model("Base")} { + leaf: Leaf; + } + + @test model ${t.model("Derived")} extends Base { + payload: Indexed; + } + + @test model ${t.model("CycleA")} { + next: CycleB; + } + + @test model ${t.model("CycleB")} { + prev: CycleA; + } + `, + ); + + const models = [Derived, Indexed, Leaf, Base, CycleA, CycleB] as Type[]; + const set = new SCCSet(typeDependencyConnector); + for (const type of models) { + set.add(type); + } + + const itemNames = set.items.map(getTypeLabel); + expect(itemNames).toEqual(["Leaf", "Indexed", "Base", "Derived", "CycleA", "CycleB"]); + + const componentNames = set.components.map(formatComponent); + expect(componentNames).toEqual(["Leaf", "Indexed", "Base", "Derived", ["CycleA", "CycleB"]]); + }); +}); + +function componentValues(set: SCCSet): NestedArray[] { + return componentValuesFrom(set.components); +} + +function componentValuesFrom(components: readonly SCCComponent[]): NestedArray[] { + return components.map((component) => component.value); +} + +function getTypeLabel(type: Type): string { + if ("name" in type && typeof type.name === "string" && type.name) { + return type.name; + } + return type.kind; +} + +type ComponentLabel = string | string[]; + +function formatComponent(component: SCCComponent): ComponentLabel { + return formatComponentValue(component.value); +} + +function formatComponentValue(componentValue: NestedArray): ComponentLabel { + if (Array.isArray(componentValue)) { + return (componentValue as Type[]).map(getTypeLabel); + } + return getTypeLabel(componentValue); +} diff --git a/packages/emitter-framework/src/core/scc-set.ts b/packages/emitter-framework/src/core/scc-set.ts new file mode 100644 index 00000000000..dafd907c1a0 --- /dev/null +++ b/packages/emitter-framework/src/core/scc-set.ts @@ -0,0 +1,777 @@ +import { shallowReactive } from "@alloy-js/core"; + +export type NestedArray = T | NestedArray[]; + +export interface SCCComponent { + /** + * Nested array representation of the items that belong to this component. + * Single-node components expose the item directly while cycles expose a nested array. + */ + readonly value: NestedArray; + /** Components that this component depends on (outgoing edges). */ + readonly references: ReadonlySet>; + /** Components that depend on this component (incoming edges). */ + readonly referencedBy: ReadonlySet>; +} + +type Connector = (item: T) => Iterable; + +export interface SCCSetOptions { + /** + * When true, every node reachable from an added node is automatically surfaced + * in the public `items`/`components` lists without requiring an explicit add. + */ + includeReachable?: boolean; +} + +interface ComponentRecord { + nodes: NodeRecord[]; + value: NestedArray; + size: number; + view: ComponentView; +} + +interface ComponentView extends SCCComponent { + readonly references: Set>; + readonly referencedBy: Set>; +} + +interface NodeRecord { + readonly item: T; + readonly neighbors: Set>; + readonly dependents: Set>; + added: boolean; + addedAt?: number; + component?: ComponentRecord; + initialized: boolean; +} + +interface RemovedComponent { + component: ComponentRecord; + index: number; +} + +/** + * Maintains a growing directed graph and exposes its strongly connected components (SCCs). + * + * The set incrementally applies Tarjan's algorithm so newly added nodes immediately update + * the public `items` and `components` views. Both arrays are shallow reactive so observers + * can hold references without re-fetching after each mutation. + */ +export class SCCSet { + /** + * Flattened, topologically ordered view of every node that has been added to the set. + * Nodes appear before dependents unless they belong to the same strongly connected component. + */ + public readonly items: T[]; + + /** + * Ordered strongly connected components that mirror `items`. Each entry exposes its members along + * with the components it depends on and the components that depend on it, enabling callers to walk + * the connectivity graph directly from any component. + */ + public readonly components: SCCComponent[]; + + readonly #nodes = new Map>(); + readonly #connector: Connector; + readonly #componentOrder: ComponentRecord[] = []; + #addCounter = 0; + readonly #includeReachable: boolean; + + /** + * Creates a new SCC set around the provided dependency connector function. + * @param connector Maps each item to the items it depends on (outgoing edges). + * @param options Controls automatic inclusion of reachable nodes. + */ + constructor(connector: Connector, options: SCCSetOptions = {}) { + this.#connector = connector; + this.items = shallowReactive([]); + this.components = shallowReactive[]>([]); + this.#includeReachable = !!options.includeReachable; + } + + /** + * Adds an item to the graph and captures its outgoing connections via the connector. + * Items can be referenced before they are added; they will only surface in the public + * views once explicitly added. + */ + public add(item: T): void { + const node = this.#getOrCreateNode(item); + if (node.added) { + return; + } + + node.added = true; + node.addedAt = this.#addCounter++; + this.#initializeNode(node, true); + + if (this.#includeReachable) { + this.#autoAddReachable(node); + this.#recomputeAll(); + } else { + this.#integrateNode(node); + } + } + + /** + * Adds multiple items and recomputes SCC ordering once at the end. + */ + public addAll(items: Iterable): void { + const newlyAdded: NodeRecord[] = []; + for (const item of items) { + const node = this.#getOrCreateNode(item); + if (node.added) { + continue; + } + node.added = true; + node.addedAt = this.#addCounter++; + this.#initializeNode(node, true); + newlyAdded.push(node); + } + + if (newlyAdded.length === 0) { + return; + } + + if (this.#includeReachable) { + for (const node of newlyAdded) { + this.#autoAddReachable(node); + } + } + + this.#recomputeAll(); + } + + /** + * Recursively adds every node reachable from the starting node, initializing metadata as needed. + */ + #autoAddReachable(start: NodeRecord): void { + const visited = new Set>([start]); + const stack = [...start.neighbors]; + + while (stack.length > 0) { + const current = stack.pop()!; + if (visited.has(current)) { + continue; + } + visited.add(current); + + if (!current.added) { + current.added = true; + current.addedAt = this.#addCounter++; + this.#initializeNode(current, true); + } + + for (const neighbor of current.neighbors) { + if (!visited.has(neighbor)) { + stack.push(neighbor); + } + } + } + } + + /** + * Retrieves the cached node for the provided item or materializes a new, uninitialized record. + */ + #getOrCreateNode(item: T): NodeRecord { + let existing = this.#nodes.get(item); + if (!existing) { + existing = { + item, + neighbors: new Set>(), + dependents: new Set>(), + added: false, + initialized: false, + } satisfies NodeRecord; + this.#nodes.set(item, existing); + } + return existing; + } + + /** + * Runs the connector for the node to refresh its neighbors and dependent relationships. + * @param force When true, existing neighbor edges are cleared before recomputing. + */ + #initializeNode(node: NodeRecord, force = false): void { + if (!force && node.initialized) { + return; + } + + if (force || node.initialized) { + for (const neighbor of node.neighbors) { + neighbor.dependents.delete(node); + } + node.neighbors.clear(); + } + + const dependencies = this.#connector(node.item); + node.initialized = true; + for (const dependency of dependencies) { + if (dependency === undefined) { + throw new Error( + `Connector returned undefined dependency while initializing ${String(node.item)}`, + ); + } + const neighbor = this.#getOrCreateNode(dependency); + node.neighbors.add(neighbor); + neighbor.dependents.add(node); + if (!neighbor.added) { + this.#initializeNode(neighbor); + } + } + } + + /** + * Inserts a node that was just added into the component ordering without recomputing the world. + */ + #integrateNode(node: NodeRecord): void { + const forward = this.#collectReachable(node, (current) => current.neighbors); + const backward = this.#collectReachable(node, (current) => current.dependents); + const candidates = new Set>(); + for (const seen of forward) { + if (backward.has(seen)) { + candidates.add(seen); + } + } + candidates.add(node); + + const orderedNodes = Array.from(candidates).sort( + (left, right) => (left.addedAt ?? 0) - (right.addedAt ?? 0), + ); + + const dependencyComponents = this.#collectNeighboringComponents( + orderedNodes, + (nodeRecord) => nodeRecord.neighbors, + candidates, + ); + const dependentComponents = this.#collectNeighboringComponents( + orderedNodes, + (nodeRecord) => nodeRecord.dependents, + candidates, + ); + + const dependentClosure = this.#collectDependentComponentClosure(orderedNodes, candidates); + const sortedDependents = this.#sortComponentsTopologically(dependentClosure); + + const insertIndexBeforeRemoval = this.#computeInsertIndex( + dependencyComponents, + dependentComponents, + ); + const componentsToRemove = new Set>(); + for (const member of candidates) { + if (member.component) { + componentsToRemove.add(member.component); + } + } + for (const component of dependentClosure) { + componentsToRemove.add(component); + } + + const removedComponents = this.#removeComponents(componentsToRemove); + const newComponent = this.#createComponent(orderedNodes); + const insertIndex = this.#adjustInsertIndex(insertIndexBeforeRemoval, removedComponents); + this.#insertComponent(newComponent, insertIndex); + + let nextIndex = insertIndex + 1; + for (const component of sortedDependents) { + this.#insertComponent(component, nextIndex++); + } + + this.#refreshComponentConnections(); + } + + /** + * Walks the graph in the provided direction to find all reachable, added nodes. + */ + #collectReachable( + start: NodeRecord, + next: (node: NodeRecord) => Iterable>, + ): Set> { + const visited = new Set>(); + const stack: NodeRecord[] = [start]; + while (stack.length > 0) { + const current = stack.pop()!; + if (visited.has(current) || !current.added) { + continue; + } + visited.add(current); + for (const neighbor of next(current)) { + if (neighbor.added && !visited.has(neighbor)) { + stack.push(neighbor); + } + } + } + return visited; + } + + /** + * Collects components adjacent to the provided nodes that are not part of an excluded set. + */ + #collectNeighboringComponents( + nodes: NodeRecord[], + next: (node: NodeRecord) => Iterable>, + excluded: Set>, + ): Set> { + const components = new Set>(); + for (const node of nodes) { + for (const neighbor of next(node)) { + if (!neighbor.added || excluded.has(neighbor) || !neighbor.component) { + continue; + } + components.add(neighbor.component); + } + } + return components; + } + + /** + * Computes the closure of components that depend (directly or indirectly) on the start nodes. + */ + #collectDependentComponentClosure( + startNodes: NodeRecord[], + excluded: Set>, + ): Set> { + const closure = new Set>(); + const visited = new Set>(); + const stack = [...startNodes]; + + while (stack.length > 0) { + const current = stack.pop()!; + if (visited.has(current)) { + continue; + } + visited.add(current); + + for (const dependent of current.dependents) { + if (excluded.has(dependent) || visited.has(dependent)) { + continue; + } + + if (dependent.added && dependent.component) { + if (!closure.has(dependent.component)) { + closure.add(dependent.component); + for (const member of dependent.component.nodes) { + stack.push(member); + } + } + } else { + stack.push(dependent); + } + } + } + + return closure; + } + + /** + * Sorts the provided components in topological order, falling back to insertion order on cycles. + */ + #sortComponentsTopologically(components: Set>): ComponentRecord[] { + if (components.size === 0) { + return []; + } + + const componentList = Array.from(components); + const inDegree = new Map, number>(); + const adjacency = new Map, Set>>(); + + for (const component of componentList) { + inDegree.set(component, 0); + adjacency.set(component, new Set()); + } + + for (const component of componentList) { + for (const node of component.nodes) { + for (const dependent of node.dependents) { + const dependentComponent = dependent.component; + if (!dependentComponent || dependentComponent === component) { + continue; + } + if (components.has(dependentComponent)) { + if (!adjacency.get(component)!.has(dependentComponent)) { + adjacency.get(component)!.add(dependentComponent); + inDegree.set(dependentComponent, (inDegree.get(dependentComponent) ?? 0) + 1); + } + } + } + } + } + + const queue = componentList + .filter((component) => (inDegree.get(component) ?? 0) === 0) + .sort((left, right) => this.#compareComponentAddedAt(left, right)); + const ordered: ComponentRecord[] = []; + while (queue.length > 0) { + const current = queue.shift()!; + ordered.push(current); + for (const neighbor of adjacency.get(current) ?? []) { + const remaining = (inDegree.get(neighbor) ?? 0) - 1; + inDegree.set(neighbor, remaining); + if (remaining === 0) { + queue.push(neighbor); + queue.sort((left, right) => this.#compareComponentAddedAt(left, right)); + } + } + } + + if (ordered.length !== components.size) { + return componentList.sort((left, right) => this.#compareComponentAddedAt(left, right)); + } + + return ordered; + } + + /** + * Orders components by the earliest time any of their nodes were added to the set. + */ + #compareComponentAddedAt(left: ComponentRecord, right: ComponentRecord): number { + return this.#getComponentAddedAt(left) - this.#getComponentAddedAt(right); + } + + /** + * Returns the earliest add-counter value for nodes within the component. + */ + #getComponentAddedAt(component: ComponentRecord): number { + return component.nodes.reduce( + (min, node) => Math.min(min, node.addedAt ?? Number.POSITIVE_INFINITY), + Number.POSITIVE_INFINITY, + ); + } + + /** + * Determines where a new component should be inserted so dependency ordering stays valid. + */ + #computeInsertIndex( + dependencies: Set>, + dependents: Set>, + ): number { + const dependencyIndex = dependencies.size + ? Math.max(...Array.from(dependencies, (component) => this.#getComponentIndex(component))) + : -1; + const lowerBound = dependencyIndex + 1; + if (!dependents.size) { + if (!dependencies.size) { + return this.#componentOrder.length; + } + return Math.min(lowerBound, this.#componentOrder.length); + } + + const upperBound = Math.min( + ...Array.from(dependents, (component) => this.#getComponentIndex(component)), + ); + if (upperBound < lowerBound) { + return lowerBound; + } + return upperBound; + } + + /** + * Retrieves the current ordering index for the component, throwing if it is unknown. + */ + #getComponentIndex(component: ComponentRecord): number { + const index = this.#componentOrder.indexOf(component); + if (index === -1) { + throw new Error("Component not found in order."); + } + return index; + } + + /** + * Calculates the position in `items` where the first element of a component at index would live. + */ + #getItemsStartIndexForInsert(targetIndex: number): number { + let start = 0; + for (let i = 0; i < targetIndex; i++) { + start += this.#componentOrder[i].size; + } + return start; + } + + /** + * Convenience helper for `getItemsStartIndexForInsert` that names the intent for existing indices. + */ + #getItemsStartIndexForIndex(componentIndex: number): number { + return this.#getItemsStartIndexForInsert(componentIndex); + } + + /** + * Removes the specified components from both the ordering list and flattened items array. + * Returns metadata describing what was removed so later insertions can adjust their offsets. + */ + #removeComponents(components: Set>): RemovedComponent[] { + if (components.size === 0) { + return []; + } + + const indexed = Array.from(components, (component) => ({ + component, + index: this.#getComponentIndex(component), + })).sort((a, b) => b.index - a.index); + + const removed: RemovedComponent[] = []; + for (const { component, index } of indexed) { + const startIndex = this.#getItemsStartIndexForIndex(index); + this.#componentOrder.splice(index, 1); + this.components.splice(index, 1); + this.items.splice(startIndex, component.size); + component.view.references.clear(); + component.view.referencedBy.clear(); + for (const node of component.nodes) { + node.component = undefined; + } + removed.push({ component, index }); + } + + removed.sort((a, b) => a.index - b.index); + return removed; + } + + /** + * Adjusts a desired insertion point to account for previously removed components. + */ + #adjustInsertIndex(desiredIndex: number, removed: RemovedComponent[]): number { + let shift = 0; + for (const removedComponent of removed) { + if (removedComponent.index < desiredIndex) { + shift++; + } + } + return Math.max(0, desiredIndex - shift); + } + + /** + * Inserts a component into the ordering and mirrors the change in the public lists. + */ + #insertComponent(component: ComponentRecord, index: number): void { + const startIndex = this.#getItemsStartIndexForInsert(index); + for (const node of component.nodes) { + node.component = component; + } + this.#componentOrder.splice(index, 0, component); + this.components.splice(index, 0, component.view); + const items = component.nodes.map((record) => record.item); + this.items.splice(startIndex, 0, ...items); + } + + /** + * Builds a component record for the provided nodes and assigns the back-reference on each node. + */ + #createComponent(nodes: NodeRecord[]): ComponentRecord { + const value = this.#createComponentValue(nodes); + const view: ComponentView = { + value, + references: new Set>(), + referencedBy: new Set>(), + }; + const component: ComponentRecord = { + nodes, + value, + size: nodes.length, + view, + }; + for (const node of nodes) { + node.component = component; + } + return component; + } + + /** + * Generates the structure stored in `components` for the given nodes (item vs. nested array). + */ + #createComponentValue(nodes: NodeRecord[]): NestedArray { + if (nodes.length === 1) { + return nodes[0].item; + } + const items = nodes.map((record) => record.item); + return shallowReactive(items) as NestedArray; + } + + /** + * Rebuilds the complete SCC ordering from scratch using Tarjan's algorithm and updates outputs. + */ + #recomputeAll(): void { + const nodes = Array.from(this.#nodes.values()).filter((node) => node.added); + for (const node of nodes) { + node.component = undefined; + } + + if (nodes.length === 0) { + for (const component of this.#componentOrder) { + component.view.references.clear(); + component.view.referencedBy.clear(); + } + this.#componentOrder.length = 0; + this.components.length = 0; + this.items.length = 0; + return; + } + + const indexMap = new Map, number>(); + const lowlinkMap = new Map, number>(); + const stack: NodeRecord[] = []; + const onStack = new Set>(); + let index = 0; + const components: ComponentRecord[] = []; + + const stronglyConnect = (node: NodeRecord): void => { + indexMap.set(node, index); + lowlinkMap.set(node, index); + index++; + stack.push(node); + onStack.add(node); + + for (const neighbor of node.neighbors) { + if (!neighbor.added) { + continue; + } + if (!indexMap.has(neighbor)) { + stronglyConnect(neighbor); + lowlinkMap.set(node, Math.min(lowlinkMap.get(node)!, lowlinkMap.get(neighbor)!)); + } else if (onStack.has(neighbor)) { + lowlinkMap.set(node, Math.min(lowlinkMap.get(node)!, indexMap.get(neighbor)!)); + } + } + + if (lowlinkMap.get(node) === indexMap.get(node)) { + const componentNodes: NodeRecord[] = []; + let member: NodeRecord; + do { + member = stack.pop()!; + onStack.delete(member); + componentNodes.push(member); + } while (member !== node); + componentNodes.sort((left, right) => (left.addedAt ?? 0) - (right.addedAt ?? 0)); + const component = this.#createComponent(componentNodes); + components.push(component); + } + }; + + for (const node of nodes) { + if (!indexMap.has(node)) { + stronglyConnect(node); + } + } + + const adjacency = new Map, Set>>(); + const inDegree = new Map, number>(); + for (const component of components) { + adjacency.set(component, new Set()); + inDegree.set(component, 0); + } + + for (const component of components) { + for (const node of component.nodes) { + const dependencyComponents = new Set>(); + const visitedNodes = new Set>(); + for (const neighbor of node.neighbors) { + this.#collectComponentDependencies(neighbor, dependencyComponents, visitedNodes); + } + for (const dependency of dependencyComponents) { + if (dependency === component) { + continue; + } + const dependents = adjacency.get(dependency)!; + if (!dependents.has(component)) { + dependents.add(component); + inDegree.set(component, (inDegree.get(component) ?? 0) + 1); + } + } + } + } + + const queue = components + .filter((component) => (inDegree.get(component) ?? 0) === 0) + .sort((left, right) => this.#compareComponentAddedAt(left, right)); + const orderedComponents: ComponentRecord[] = []; + while (queue.length > 0) { + const current = queue.shift()!; + orderedComponents.push(current); + for (const dependent of adjacency.get(current) ?? []) { + const nextDegree = (inDegree.get(dependent) ?? 0) - 1; + inDegree.set(dependent, nextDegree); + if (nextDegree === 0) { + queue.push(dependent); + queue.sort((left, right) => this.#compareComponentAddedAt(left, right)); + } + } + } + + if (orderedComponents.length !== components.length) { + orderedComponents.push( + ...components + .filter((component) => !orderedComponents.includes(component)) + .sort((left, right) => this.#compareComponentAddedAt(left, right)), + ); + } + + this.#componentOrder.splice(0, this.#componentOrder.length, ...orderedComponents); + this.components.splice( + 0, + this.components.length, + ...orderedComponents.map((component) => component.view), + ); + const flatItems: T[] = []; + for (const component of orderedComponents) { + for (const node of component.nodes) { + flatItems.push(node.item); + } + } + this.items.splice(0, this.items.length, ...flatItems); + + this.#refreshComponentConnections(); + } + + /** + * Traverses outward from a node to find components it ultimately depends on, even through + * nodes that are not yet part of the public set. + */ + #collectComponentDependencies( + node: NodeRecord, + collected: Set>, + visited: Set>, + ): void { + if (visited.has(node)) { + return; + } + visited.add(node); + + if (node.added) { + if (node.component) { + collected.add(node.component); + } + return; + } + + for (const neighbor of node.neighbors) { + this.#collectComponentDependencies(neighbor, collected, visited); + } + } + + /** + * Updates each public component view so callers can traverse the component graph without + * recomputing edges manually. + */ + #refreshComponentConnections(): void { + for (const component of this.#componentOrder) { + component.view.references.clear(); + component.view.referencedBy.clear(); + } + + for (const component of this.#componentOrder) { + for (const node of component.nodes) { + for (const neighbor of node.neighbors) { + if (!neighbor.added) { + continue; + } + const neighborComponent = neighbor.component; + if (!neighborComponent || neighborComponent === component) { + continue; + } + const dependencyView = neighborComponent.view; + component.view.references.add(dependencyView); + dependencyView.referencedBy.add(component.view); + } + } + } + } +} diff --git a/packages/emitter-framework/src/core/type-connector.ts b/packages/emitter-framework/src/core/type-connector.ts new file mode 100644 index 00000000000..adebe512625 --- /dev/null +++ b/packages/emitter-framework/src/core/type-connector.ts @@ -0,0 +1,67 @@ +import type { Type } from "@typespec/compiler"; + +/** + * Connector for {@link TypeSpec} {@link Type}s that captures the type graph edges used for + * topological ordering. Each returned dependency represents an incoming edge for the source + * type, e.g. a model depends on its base model, property types, and indexer key/value types. + */ +export function typeDependencyConnector(type: Type): Iterable { + return iterateTypeDependencies(type); +} + +function* iterateTypeDependencies(type: Type): IterableIterator { + switch (type.kind) { + case "Model": + if (type.baseModel) { + yield type.baseModel; + } + + if (type.indexer) { + yield type.indexer.key; + yield type.indexer.value; + } + + for (const property of type.properties.values()) { + yield property.type; + } + break; + case "ModelProperty": + yield type.type; + break; + case "Interface": + for (const operation of type.operations.values()) { + yield operation; + } + break; + case "Operation": + yield type.parameters; + yield type.returnType; + break; + case "Union": + for (const variant of type.variants.values()) { + yield variant; + } + break; + case "UnionVariant": + yield type.type; + break; + case "Tuple": + yield* type.values; + break; + case "Enum": + for (const member of type.members.values()) { + yield member; + } + break; + case "EnumMember": + if (type.sourceMember) { + yield type.sourceMember; + } + break; + case "Scalar": + if (type.baseScalar) { + yield type.baseScalar; + } + break; + } +} diff --git a/packages/http-canonicalization/CHANGELOG.md b/packages/http-canonicalization/CHANGELOG.md index da32270abbd..8d54df089b6 100644 --- a/packages/http-canonicalization/CHANGELOG.md +++ b/packages/http-canonicalization/CHANGELOG.md @@ -7,8 +7,6 @@ - [#9046](https://github.com/microsoft/typespec/pull/9046) Upgrade dependencies - - ## 0.13.0 ### Features @@ -22,4 +20,3 @@ ### Bug Fixes - [#8833](https://github.com/microsoft/typespec/pull/8833) Add forgotten index file. - diff --git a/packages/http-canonicalization/package.json b/packages/http-canonicalization/package.json index c0c5a37a0a4..e3b7669b4ce 100644 --- a/packages/http-canonicalization/package.json +++ b/packages/http-canonicalization/package.json @@ -31,6 +31,7 @@ "license": "MIT", "description": "", "dependencies": { + "@typespec/emitter-framework": "workspace:^", "@typespec/mutator-framework": "workspace:^" }, "peerDependencies": { diff --git a/packages/http-canonicalization/src/codecs.ts b/packages/http-canonicalization/src/codecs.ts index 3e5f559be3f..261fc28e1a0 100644 --- a/packages/http-canonicalization/src/codecs.ts +++ b/packages/http-canonicalization/src/codecs.ts @@ -1,29 +1,38 @@ -import { getEncode, type MemberType, type Program, type Type } from "@typespec/compiler"; +import { + getEncode, + getFriendlyName, + type MemberType, + type ModelProperty, + type Program, + type Type, +} from "@typespec/compiler"; import type { Typekit } from "@typespec/compiler/typekit"; import { isHeader } from "@typespec/http"; -import type { HttpCanonicalization } from "./http-canonicalization-classes.js"; -export interface CodecEncodeResult { +export interface EncodingInfo { codec: Codec; - encodedType: Type; + languageType: Type; + wireType: Type; } + export class CodecRegistry { $: Typekit; - #codecs: (typeof Codec)[]; + #codecs: Codec[]; + constructor($: Typekit) { - this.#codecs = []; this.$ = $; + this.#codecs = []; } - addCodec(codec: typeof Codec) { + addCodec(codec: Codec) { this.#codecs.push(codec); } - detect(type: HttpCanonicalization): Codec { + encode(sourceType: Type, referenceTypes: MemberType[]): EncodingInfo { for (const codec of this.#codecs) { - const codecInstance = codec.detect(this.$, type); - if (codecInstance) { - return codecInstance; + const result = codec.encode(this.$, sourceType, referenceTypes); + if (result) { + return { codec, ...result }; } } @@ -33,19 +42,12 @@ export class CodecRegistry { export abstract class Codec { abstract id: string; - canonicalization: HttpCanonicalization; - $: Typekit; - - constructor($: Typekit, canonicalization: HttpCanonicalization) { - this.canonicalization = canonicalization; - this.$ = $; - } - static detect($: Typekit, canonicalization: HttpCanonicalization): Codec | undefined { - return undefined; - } - - abstract encode(): { languageType: Type; wireType: Type }; + abstract encode( + $: Typekit, + sourceType: Type, + referenceTypes: MemberType[], + ): { languageType: Type; wireType: Type } | null; static getMetadata< TTypeSource extends Type, @@ -84,103 +86,88 @@ export abstract class Codec { export class IdentityCodec extends Codec { readonly id = "identity"; - static detect($: Typekit, canonicalization: HttpCanonicalization) { - return new IdentityCodec($, canonicalization); - } - encode() { + encode($: Typekit, sourceType: Type, referenceTypes: MemberType[]) { return { - wireType: this.canonicalization.sourceType, - languageType: this.canonicalization.sourceType, + wireType: sourceType, + languageType: sourceType, }; } } export class UnixTimestamp64Codec extends Codec { readonly id = "unix-timestamp-64"; - static detect($: Typekit, canonicalization: HttpCanonicalization) { - const type = canonicalization.sourceType; - if (!$.scalar.is(type) || !$.type.isAssignableTo(type, $.builtin.utcDateTime)) { - return; + encode($: Typekit, sourceType: Type, referenceTypes: MemberType[]) { + if (!$.scalar.is(sourceType) || !$.type.isAssignableTo(sourceType, $.builtin.utcDateTime)) { + return null; } - const encodingInfo = this.getMetadata( + const encodingInfo = Codec.getMetadata( $, - type, - canonicalization.referenceTypes, + sourceType, + referenceTypes, $.modelProperty.is, getEncode, ); if (!encodingInfo) { - return; + return null; } if (encodingInfo.encoding === "unix-timestamp" && encodingInfo.type === $.builtin.int64) { - return new UnixTimestamp64Codec($, canonicalization); + return { + languageType: $.builtin.utcDateTime, + wireType: $.builtin.float64, + }; } - } - encode() { - return { - languageType: this.$.builtin.int64, - wireType: this.$.builtin.float64, - }; + return null; } } export class UnixTimestamp32Codec extends Codec { readonly id = "unix-timestamp-32"; - static detect($: Typekit, canonicalization: HttpCanonicalization) { - const type = canonicalization.sourceType; - if (!$.scalar.is(type) || !$.type.isAssignableTo(type, $.builtin.utcDateTime)) { - return; + encode($: Typekit, sourceType: Type, referenceTypes: MemberType[]) { + if (!$.scalar.is(sourceType) || !$.type.isAssignableTo(sourceType, $.builtin.utcDateTime)) { + return null; } - const encodingInfo = this.getMetadata( + const encodingInfo = Codec.getMetadata( $, - type, - canonicalization.referenceTypes, + sourceType, + referenceTypes, $.modelProperty.is, getEncode, ); if (!encodingInfo) { - return; + return null; } - if (encodingInfo.encoding === "unix-timestamp" && encodingInfo.type === $.builtin.int32) { - return new UnixTimestamp32Codec($, canonicalization); + if (encodingInfo.encoding === "unixTimestamp" && encodingInfo.type === $.builtin.int32) { + return { + languageType: $.builtin.utcDateTime, + wireType: $.builtin.float64, + }; } - } - encode() { - return { - languageType: this.$.builtin.int32, - wireType: this.$.builtin.float64, - }; + return null; } } export class Rfc3339Codec extends Codec { readonly id = "rfc3339"; - static detect($: Typekit, canonicalization: HttpCanonicalization) { - const type = canonicalization.sourceType; - - if (!$.scalar.is(type) || !$.type.isAssignableTo(type, $.builtin.utcDateTime)) { - return; + encode($: Typekit, sourceType: Type, referenceTypes: MemberType[]) { + if (!$.scalar.is(sourceType) || !$.type.isAssignableTo(sourceType, $.builtin.utcDateTime)) { + return null; } - return new Rfc3339Codec($, canonicalization); - } - - encode() { return { - languageType: this.canonicalization.sourceType, - wireType: this.$.builtin.string, + languageType: sourceType, + wireType: $.builtin.string, }; } } @@ -188,157 +175,190 @@ export class Rfc3339Codec extends Codec { export class Rfc7231Codec extends Codec { readonly id = "rfc7231"; - static detect($: Typekit, canonicalization: HttpCanonicalization) { - const type = canonicalization.sourceType; - - if (!$.scalar.is(type) || !$.type.isAssignableTo(type, $.builtin.utcDateTime)) { - return; + encode($: Typekit, sourceType: Type, referenceTypes: MemberType[]) { + if (!$.scalar.is(sourceType) || !$.type.isAssignableTo(sourceType, $.builtin.utcDateTime)) { + return null; } - const encodingInfo = this.getMetadata( + const encodingInfo = Codec.getMetadata( $, - type, - canonicalization.referenceTypes, + sourceType, + referenceTypes, $.modelProperty.is, getEncode, ); if (!encodingInfo) { - if ( - this.getMetadata( - $, - undefined, - canonicalization.referenceTypes, - $.modelProperty.is, - isHeader, - ) - ) { - return new Rfc7231Codec($, canonicalization); + if (Codec.getMetadata($, undefined, referenceTypes, $.modelProperty.is, isHeader)) { + return { + languageType: sourceType, + wireType: $.builtin.string, + }; } - return; + return null; } if (encodingInfo.encoding === "rfc7231") { - return new Rfc7231Codec($, canonicalization); + return { + languageType: sourceType, + wireType: $.builtin.string, + }; } - } - encode() { - return { - languageType: this.canonicalization.sourceType, - wireType: this.$.builtin.string, - }; + return null; } } export class Base64Codec extends Codec { readonly id = "base64"; - static detect($: Typekit, canonicalization: HttpCanonicalization) { - const type = canonicalization.sourceType; - - if (!$.type.isAssignableTo(type, $.builtin.bytes)) { - return; + encode($: Typekit, sourceType: Type, referenceTypes: MemberType[]) { + if (!$.type.isAssignableTo(sourceType, $.builtin.bytes)) { + return null; } - return new Base64Codec($, canonicalization); - } - - encode() { return { - languageType: this.canonicalization.sourceType, - wireType: this.$.builtin.string, + languageType: sourceType, + wireType: $.builtin.string, }; } } +export interface CoerceToFloat64CodecOptions { + lossyInteger?: boolean; + lossyDecimal?: boolean; +} + export class CoerceToFloat64Codec extends Codec { readonly id = "coerce-to-float64"; + options: CoerceToFloat64CodecOptions; + constructor(options: CoerceToFloat64CodecOptions = {}) { + super(); + this.options = options; + } - static detect($: Typekit, canonicalization: HttpCanonicalization) { - const type = canonicalization.sourceType; - - if (!$.type.isAssignableTo(type, $.builtin.numeric)) { - return; + encode($: Typekit, sourceType: Type, referenceTypes: MemberType[]) { + if ( + this.options.lossyInteger && + this.options.lossyDecimal && + !$.type.isAssignableTo(sourceType, $.builtin.numeric) + ) { + return null; + } else if ( + this.options.lossyInteger && + !$.scalar.extendsInteger(sourceType) && + !$.scalar.extendsFloat(sourceType) + ) { + return null; + } else if ( + this.options.lossyDecimal && + !$.scalar.extendsDecimal(sourceType) && + !$.scalar.extendsFloat(sourceType) + ) { + return null; + } else if ( + !$.scalar.extendsFloat(sourceType) && + !$.scalar.extendsInt32(sourceType) && + !$.scalar.extendsUint32(sourceType) + ) { + return null; } - return new CoerceToFloat64Codec($, canonicalization); - } - - encode() { return { - languageType: this.canonicalization.sourceType, - wireType: this.$.builtin.float64, + languageType: sourceType, + wireType: $.builtin.float64, }; } } -export class NumericToStringCodec extends Codec { - readonly id = "numeric-to-string"; - - static detect($: Typekit, canonicalization: HttpCanonicalization) { - const type = canonicalization.sourceType; +export class ArrayJoinCodec extends Codec { + readonly id = "array-join"; - if (!$.type.isAssignableTo(type, $.builtin.numeric)) { - return; + encode($: Typekit, sourceType: Type, referenceTypes: MemberType[]) { + if (!$.array.is(sourceType)) { + return null; } - return new NumericToStringCodec($, canonicalization); - } - - encode() { + // Note: This codec previously checked canonicalization.options.location + // This logic may need to be refactored to pass location info differently return { - languageType: this.canonicalization.sourceType, - wireType: this.$.builtin.string, + languageType: sourceType, + wireType: $.builtin.string, }; } } -export class ArrayJoinCodec extends Codec { - readonly id = "array-join"; - static detect($: Typekit, canonicalization: HttpCanonicalization) { - const type = canonicalization.sourceType; +interface RenameCodecOptions { + namer?(type: Type): string | undefined; +} +/** + * Renames the language type according to the language's name policy and + * friendly name decorator. + */ +export class RenameCodec extends Codec { + readonly id = "model-property-rename"; + options: RenameCodecOptions; + + constructor(options: RenameCodecOptions = {}) { + super(); + this.options = options; + } - if (!$.array.is(type)) { - return; + encode($: Typekit, sourceType: Type, referenceTypes: MemberType[]) { + if (!$.modelProperty.is(sourceType)) { + return null; } - if ( - canonicalization.options.location === "query" || - canonicalization.options.location === "header" || - canonicalization.options.location === "path" - ) { - return new ArrayJoinCodec($, canonicalization); + if (!("name" in sourceType)) { + return null; } - } - encode() { - return { - languageType: this.canonicalization.sourceType, - wireType: this.$.builtin.string, - }; + const friendlyName = getFriendlyName($.program, sourceType); + if (friendlyName && friendlyName !== sourceType.name) { + const clonedProp = $.type.clone(sourceType as ModelProperty); + clonedProp.name = friendlyName; + return { + languageType: clonedProp, + wireType: sourceType, + }; + } + + if (this.options.namer) { + const name = this.options.namer(sourceType); + if (name && name !== sourceType.name) { + const clonedProp = $.type.clone(sourceType as ModelProperty); + clonedProp.name = name; + $.type.finishType(clonedProp); + return { + languageType: clonedProp, + wireType: sourceType, + }; + } + } + + return null; } } -const jsonEncoderRegistryCache = new WeakMap(); - -export const getJsonEncoderRegistry = ($: Typekit) => { - if (jsonEncoderRegistryCache.has($.program)) { - return jsonEncoderRegistryCache.get($.program)!; +const jsonCodecRegistryCache = new WeakMap(); +export const getJsonCodecRegistry = ($: Typekit) => { + if (jsonCodecRegistryCache.has($.program)) { + return jsonCodecRegistryCache.get($.program)!; } const registry = new CodecRegistry($); - registry.addCodec(Rfc7231Codec); - registry.addCodec(Rfc3339Codec); - registry.addCodec(UnixTimestamp32Codec); - registry.addCodec(UnixTimestamp64Codec); - registry.addCodec(Base64Codec); - registry.addCodec(CoerceToFloat64Codec); - registry.addCodec(NumericToStringCodec); - registry.addCodec(ArrayJoinCodec); - registry.addCodec(IdentityCodec); - - jsonEncoderRegistryCache.set($.program, registry); + registry.addCodec(new CoerceToFloat64Codec()); + registry.addCodec(new Rfc7231Codec()); + registry.addCodec(new UnixTimestamp32Codec()); + registry.addCodec(new UnixTimestamp64Codec()); + registry.addCodec(new Rfc3339Codec()); + registry.addCodec(new Base64Codec()); + registry.addCodec(new Base64Codec()); + registry.addCodec(new ArrayJoinCodec()); + registry.addCodec(new RenameCodec()); + registry.addCodec(new IdentityCodec()); + + jsonCodecRegistryCache.set($.program, registry); return registry; }; diff --git a/packages/http-canonicalization/src/enum-member.test.ts b/packages/http-canonicalization/src/enum-member.test.ts new file mode 100644 index 00000000000..b2e3eb1b12a --- /dev/null +++ b/packages/http-canonicalization/src/enum-member.test.ts @@ -0,0 +1,75 @@ +import { t, type TesterInstance } from "@typespec/compiler/testing"; +import { $ } from "@typespec/compiler/typekit"; +import { Visibility } from "@typespec/http"; +import { beforeEach, expect, it } from "vitest"; +import { Tester } from "../test/test-host.js"; +import { EnumMemberHttpCanonicalization } from "./enum-member.js"; +import { EnumHttpCanonicalization } from "./enum.js"; +import { HttpCanonicalizer } from "./http-canonicalization.js"; + +let runner: TesterInstance; + +beforeEach(async () => { + runner = await Tester.createInstance(); +}); + +it("canonicalizes enum members correctly", async () => { + const { Color, program } = await runner.compile(t.code` + enum ${t.enum("Color")} { Red, Green, Blue } + `); + + const tk = $(program); + const engine = new HttpCanonicalizer(tk); + + const canonical = engine.canonicalize(Color, { + visibility: Visibility.Read, + }) as EnumHttpCanonicalization; + + const redMember = canonical.members.get("Red")!; + + expect(redMember).toBeInstanceOf(EnumMemberHttpCanonicalization); + expect(redMember.isDeclaration).toBe(true); + expect(redMember.codec).toBe(null); + + // Language and wire types should be the enum member + expect(redMember.languageType.name).toBe("Red"); + expect(redMember.wireType.name).toBe("Red"); +}); + +it("enum member has correct source type", async () => { + const { Status, program } = await runner.compile(t.code` + enum ${t.enum("Status")} { + Active: "active", + Inactive: "inactive" + } + `); + + const tk = $(program); + const engine = new HttpCanonicalizer(tk); + + const canonical = engine.canonicalize(Status, { + visibility: Visibility.Read, + }) as EnumHttpCanonicalization; + + const activeMember = canonical.members.get("Active")!; + + expect(activeMember.sourceType.name).toBe("Active"); + expect(activeMember.sourceType.value).toBe("active"); +}); + +it("enum member uses identity codec for subgraph", async () => { + const { Color, program } = await runner.compile(t.code` + enum ${t.enum("Color")} { Red, Green, Blue } + `); + + const tk = $(program); + const engine = new HttpCanonicalizer(tk); + + const canonical = engine.canonicalize(Color, { + visibility: Visibility.Read, + }) as EnumHttpCanonicalization; + + const redMember = canonical.members.get("Red")!; + + expect(redMember.subgraphUsesIdentityCodec()).toBe(true); +}); diff --git a/packages/http-canonicalization/src/enum-member.ts b/packages/http-canonicalization/src/enum-member.ts new file mode 100644 index 00000000000..a5ef40625a5 --- /dev/null +++ b/packages/http-canonicalization/src/enum-member.ts @@ -0,0 +1,109 @@ +import type { EnumMember, MemberType } from "@typespec/compiler"; +import { + EnumMemberMutation, + MutationHalfEdge, + type MutationNodeForType, + type MutationTraits, +} from "@typespec/mutator-framework"; +import type { Codec } from "./codecs.js"; +import type { HttpCanonicalizationMutations } from "./http-canonicalization-classes.js"; +import type { + CanonicalizationPredicate, + HttpCanonicalizationCommon, + HttpCanonicalizationInfo, + HttpCanonicalizer, +} from "./http-canonicalization.js"; +import { HttpCanonicalizationOptions } from "./options.js"; + +/** + * Canonicalizes enum member types for HTTP. + */ +export class EnumMemberHttpCanonicalization + extends EnumMemberMutation< + HttpCanonicalizationOptions, + HttpCanonicalizationMutations, + HttpCanonicalizer + > + implements HttpCanonicalizationCommon +{ + isDeclaration: boolean = false; + codec: Codec | null = null; + + #languageMutationNode: MutationNodeForType; + #wireMutationNode: MutationNodeForType; + + get languageMutationNode() { + return this.#languageMutationNode; + } + + get wireMutationNode() { + return this.#wireMutationNode; + } + + get languageType() { + return this.#languageMutationNode.mutatedType; + } + + get wireType() { + return this.#wireMutationNode.mutatedType; + } + + /** + * Tests whether the subgraph rooted at this canonicalization uses only + * the identity codec (no transformation). + */ + subgraphUsesIdentityCodec(): boolean { + return this.engine.subgraphUsesIdentityCodec(this); + } + + /** + * Tests whether the subgraph rooted at this canonicalization satisfies + * the provided predicate. + */ + subgraphMatchesPredicate(predicate: CanonicalizationPredicate): boolean { + return this.engine.subgraphMatchesPredicate(this, predicate); + } + + static mutationInfo( + engine: HttpCanonicalizer, + sourceType: EnumMember, + referenceTypes: MemberType[], + options: HttpCanonicalizationOptions, + halfEdge?: MutationHalfEdge, + traits?: MutationTraits, + ): HttpCanonicalizationInfo { + return { + mutationKey: options.mutationKey, + codec: null as any, // EnumMembers don't need a codec + isSynthetic: traits?.isSynthetic, + }; + } + + constructor( + engine: HttpCanonicalizer, + sourceType: EnumMember, + referenceTypes: MemberType[], + options: HttpCanonicalizationOptions, + info: HttpCanonicalizationInfo, + ) { + super(engine, sourceType, referenceTypes, options, info); + this.options = options; + this.#languageMutationNode = this.engine.getMutationNode( + this.sourceType, + info.mutationKey + "-language", + ); + this.#wireMutationNode = this.engine.getMutationNode( + this.sourceType, + info.mutationKey + "-wire", + ); + this.isDeclaration = !!this.sourceType.name; + } + + /** + * Canonicalize this enum member for HTTP. + * EnumMember is a leaf type with no children to mutate. + */ + mutate() { + // EnumMember is a leaf type with no children to mutate + } +} diff --git a/packages/http-canonicalization/src/enum.test.ts b/packages/http-canonicalization/src/enum.test.ts new file mode 100644 index 00000000000..ba2eadfac6e --- /dev/null +++ b/packages/http-canonicalization/src/enum.test.ts @@ -0,0 +1,148 @@ +import { expectTypeEquals, t, type TesterInstance } from "@typespec/compiler/testing"; +import { $ } from "@typespec/compiler/typekit"; +import { Visibility } from "@typespec/http"; +import { beforeEach, expect, it } from "vitest"; +import { Tester } from "../test/test-host.js"; +import { EnumMemberHttpCanonicalization } from "./enum-member.js"; +import { EnumHttpCanonicalization } from "./enum.js"; +import { HttpCanonicalizer } from "./http-canonicalization.js"; + +let runner: TesterInstance; + +beforeEach(async () => { + runner = await Tester.createInstance(); +}); + +it("canonicalizes a simple enum", async () => { + const { Color, program } = await runner.compile(t.code` + enum ${t.enum("Color")} { Red, Green, Blue } + `); + + const tk = $(program); + const engine = new HttpCanonicalizer(tk); + + const canonical = engine.canonicalize(Color, { + visibility: Visibility.Read, + }); + + expect(canonical).toBeInstanceOf(EnumHttpCanonicalization); + const enumCanonical = canonical as EnumHttpCanonicalization; + + // The source type should be the original enum + expectTypeEquals(enumCanonical.sourceType, Color); + + // Language and wire types should be identical for a simple enum + expectTypeEquals(enumCanonical.languageType, enumCanonical.wireType); + + // Should be a declaration + expect(enumCanonical.isDeclaration).toBe(true); + + // Should have three members + expect(enumCanonical.members.size).toBe(3); + expect(enumCanonical.members.has("Red")).toBe(true); + expect(enumCanonical.members.has("Green")).toBe(true); + expect(enumCanonical.members.has("Blue")).toBe(true); +}); + +it("canonicalizes an enum with string values", async () => { + const { Status, program } = await runner.compile(t.code` + enum ${t.enum("Status")} { + Active: "active", + Inactive: "inactive", + Pending: "pending" + } + `); + + const tk = $(program); + const engine = new HttpCanonicalizer(tk); + + const canonical = engine.canonicalize(Status, { + visibility: Visibility.Read, + }) as EnumHttpCanonicalization; + + expect(canonical.members.size).toBe(3); + + const activeCanonical = canonical.members.get("Active"); + expect(activeCanonical).toBeInstanceOf(EnumMemberHttpCanonicalization); + expect(activeCanonical!.sourceType.value).toBe("active"); +}); + +it("canonicalizes an enum with numeric values", async () => { + const { Priority, program } = await runner.compile(t.code` + enum ${t.enum("Priority")} { + Low: 1, + Medium: 2, + High: 3 + } + `); + + const tk = $(program); + const engine = new HttpCanonicalizer(tk); + + const canonical = engine.canonicalize(Priority, { + visibility: Visibility.Read, + }) as EnumHttpCanonicalization; + + expect(canonical.members.size).toBe(3); + + const lowCanonical = canonical.members.get("Low"); + expect(lowCanonical).toBeInstanceOf(EnumMemberHttpCanonicalization); + expect(lowCanonical!.sourceType.value).toBe(1); + + const highCanonical = canonical.members.get("High"); + expect(highCanonical!.sourceType.value).toBe(3); +}); + +it("enum has no codec", async () => { + const { Color, program } = await runner.compile(t.code` + enum ${t.enum("Color")} { Red, Green, Blue } + `); + + const tk = $(program); + const engine = new HttpCanonicalizer(tk); + + const canonical = engine.canonicalize(Color, { + visibility: Visibility.Read, + }) as EnumHttpCanonicalization; + + expect(canonical.codec).toBe(null); +}); + +it("uses identity codec for subgraph", async () => { + const { Color, program } = await runner.compile(t.code` + enum ${t.enum("Color")} { Red, Green, Blue } + `); + + const tk = $(program); + const engine = new HttpCanonicalizer(tk); + + const canonical = engine.canonicalize(Color, { + visibility: Visibility.Read, + }) as EnumHttpCanonicalization; + + expect(canonical.subgraphUsesIdentityCodec()).toBe(true); +}); + +it("canonicalizes enum used in model property", async () => { + const { Item, program } = await runner.compile(t.code` + enum ${t.enum("Status")} { Active, Inactive } + model ${t.model("Item")} { + status: Status; + } + `); + + const tk = $(program); + const engine = new HttpCanonicalizer(tk); + + const canonical = engine.canonicalize(Item, { + visibility: Visibility.Read, + }); + + const statusProp = canonical.properties.get("status")!; + expect(statusProp.type).toBeInstanceOf(EnumHttpCanonicalization); + + const enumType = statusProp.type as EnumHttpCanonicalization; + expect(enumType.members.size).toBe(2); + expect(enumType.members.has("Active")).toBe(true); + expect(enumType.members.has("Inactive")).toBe(true); +}); diff --git a/packages/http-canonicalization/src/enum.ts b/packages/http-canonicalization/src/enum.ts new file mode 100644 index 00000000000..0adda9edadb --- /dev/null +++ b/packages/http-canonicalization/src/enum.ts @@ -0,0 +1,115 @@ +import type { Enum, MemberType } from "@typespec/compiler"; +import { + EnumMutation, + MutationHalfEdge, + type MutationNodeForType, + type MutationTraits, +} from "@typespec/mutator-framework"; +import type { Codec } from "./codecs.js"; +import type { HttpCanonicalizationMutations } from "./http-canonicalization-classes.js"; +import type { + CanonicalizationPredicate, + HttpCanonicalizationCommon, + HttpCanonicalizationInfo, + HttpCanonicalizer, +} from "./http-canonicalization.js"; +import { HttpCanonicalizationOptions } from "./options.js"; + +/** + * Canonicalizes enum types for HTTP. + */ +export class EnumHttpCanonicalization + extends EnumMutation< + HttpCanonicalizationOptions, + HttpCanonicalizationMutations, + HttpCanonicalizer + > + implements HttpCanonicalizationCommon +{ + isDeclaration: boolean = false; + codec: Codec | null = null; + + #languageMutationNode: MutationNodeForType; + #wireMutationNode: MutationNodeForType; + + get languageMutationNode() { + return this.#languageMutationNode; + } + + get wireMutationNode() { + return this.#wireMutationNode; + } + + get languageType() { + return this.#languageMutationNode.mutatedType; + } + + get wireType() { + return this.#wireMutationNode.mutatedType; + } + + /** + * Tests whether the subgraph rooted at this canonicalization uses only + * the identity codec (no transformation). + */ + subgraphUsesIdentityCodec(): boolean { + return this.engine.subgraphUsesIdentityCodec(this); + } + + /** + * Tests whether the subgraph rooted at this canonicalization satisfies + * the provided predicate. + */ + subgraphMatchesPredicate(predicate: CanonicalizationPredicate): boolean { + return this.engine.subgraphMatchesPredicate(this, predicate); + } + + static mutationInfo( + engine: HttpCanonicalizer, + sourceType: Enum, + referenceTypes: MemberType[], + options: HttpCanonicalizationOptions, + halfEdge?: MutationHalfEdge, + traits?: MutationTraits, + ): HttpCanonicalizationInfo { + return { + mutationKey: options.mutationKey, + codec: null as any, // Enums don't need a codec + isSynthetic: traits?.isSynthetic, + }; + } + + constructor( + engine: HttpCanonicalizer, + sourceType: Enum, + referenceTypes: MemberType[], + options: HttpCanonicalizationOptions, + info: HttpCanonicalizationInfo, + ) { + super(engine, sourceType, referenceTypes, options, info); + this.options = options; + this.#languageMutationNode = this.engine.getMutationNode(this.sourceType, { + mutationKey: info.mutationKey + "-language", + isSynthetic: info.isSynthetic, + }); + this.#wireMutationNode = this.engine.getMutationNode(this.sourceType, { + mutationKey: info.mutationKey + "-wire", + isSynthetic: info.isSynthetic, + }); + this.isDeclaration = !!this.sourceType.name; + } + + protected startMemberEdge(): MutationHalfEdge { + return new MutationHalfEdge("member", this, (tail) => { + this.#languageMutationNode.connectMember(tail.languageMutationNode); + this.#wireMutationNode.connectMember(tail.wireMutationNode); + }); + } + + /** + * Canonicalize this enum for HTTP. + */ + mutate() { + super.mutateMembers(); + } +} diff --git a/packages/http-canonicalization/src/http-canonicalization-classes.ts b/packages/http-canonicalization/src/http-canonicalization-classes.ts index 7de9ca5bf62..1d0acd49a0c 100644 --- a/packages/http-canonicalization/src/http-canonicalization-classes.ts +++ b/packages/http-canonicalization/src/http-canonicalization-classes.ts @@ -1,4 +1,6 @@ import type { InstancesFor } from "@typespec/mutator-framework"; +import { EnumMemberHttpCanonicalization } from "./enum-member.js"; +import { EnumHttpCanonicalization } from "./enum.js"; import { IntrinsicHttpCanonicalization } from "./intrinsic.js"; import { LiteralHttpCanonicalization } from "./literal.js"; import { ModelPropertyHttpCanonicalization } from "./model-property.js"; @@ -16,6 +18,8 @@ export const CANONICALIZATION_CLASSES = { Union: UnionHttpCanonicalization, Intrinsic: IntrinsicHttpCanonicalization, UnionVariant: UnionVariantHttpCanonicalization, + Enum: EnumHttpCanonicalization, + EnumMember: EnumMemberHttpCanonicalization, String: LiteralHttpCanonicalization, Number: LiteralHttpCanonicalization, Boolean: LiteralHttpCanonicalization, diff --git a/packages/http-canonicalization/src/http-canonicalization.test.ts b/packages/http-canonicalization/src/http-canonicalization.test.ts index 22f14ee769c..fa24df8647e 100644 --- a/packages/http-canonicalization/src/http-canonicalization.test.ts +++ b/packages/http-canonicalization/src/http-canonicalization.test.ts @@ -1,12 +1,19 @@ -import { t } from "@typespec/compiler/testing"; +import { expectTypeEquals, t } from "@typespec/compiler/testing"; import { $ } from "@typespec/compiler/typekit"; +import { SCCSet } from "@typespec/emitter-framework"; import { Visibility } from "@typespec/http"; import { expect, it } from "vitest"; import { Tester } from "../test/test-host.js"; -import { HttpCanonicalizer } from "./http-canonicalization.js"; +import type { HttpCanonicalization } from "./http-canonicalization-classes.js"; +import { + HttpCanonicalizer, + httpCanonicalizationDependencyConnector, +} from "./http-canonicalization.js"; import type { ModelPropertyHttpCanonicalization } from "./model-property.js"; import type { ModelHttpCanonicalization } from "./model.js"; import { HttpCanonicalizationOptions } from "./options.js"; +import type { ScalarHttpCanonicalization } from "./scalar.js"; +import type { UnionHttpCanonicalization } from "./union.js"; it("canonicalizes models for read visibility", async () => { const runner = await Tester.createInstance(); @@ -27,14 +34,17 @@ it("canonicalizes models for read visibility", async () => { const read = canonicalizer.canonicalize( Foo, - new HttpCanonicalizationOptions({ visibility: Visibility.Read }), + new HttpCanonicalizationOptions({ + visibility: Visibility.Read, + contentType: "application/json", + }), ); expect(read.sourceType).toBe(Foo); // validate mutation node expect(read.properties.size).toBe(2); const deletedProperty = read.properties.get("name")! as ModelPropertyHttpCanonicalization; - expect(deletedProperty.languageType).toBe(tk.intrinsic.never); + expectTypeEquals(deletedProperty.languageType as any, tk.intrinsic.never); // validate language type expect(read.languageType.name).toBe("Foo"); @@ -81,7 +91,7 @@ it("returns the same canonicalization for the same type", async () => { model ${t.model("Foo")} { @visibility(Lifecycle.Read) createdAt: utcDateTime; name: string; - } + } `); const tk = $(program); @@ -97,3 +107,222 @@ it("returns the same canonicalization for the same type", async () => { expect(read1 === read2).toBe(true); }); + +it("handles referring to the same canonicalization", async () => { + const runner = await Tester.createInstance(); + const { Foo, Bar, Baz, program } = await runner.compile(t.code` + model ${t.model("Foo")} { + @visibility(Lifecycle.Read) createdAt: utcDateTime; + name: string; + } + + model ${t.model("Bar")} { + foo: Foo; + } + + model ${t.model("Baz")} { + foo: Foo; + } + `); + + const tk = $(program); + + const canonicalizer = new HttpCanonicalizer(tk); + + const createFoo = canonicalizer.canonicalize(Foo, { + visibility: Visibility.Create, + }) as ModelHttpCanonicalization; + + const createBar = canonicalizer.canonicalize(Bar, { + visibility: Visibility.Create, + }) as ModelHttpCanonicalization; + + expect(createBar.properties.get("foo")!.type === createFoo).toBe(true); + expectTypeEquals(createBar.properties.get("foo")!.languageType.type, createFoo.languageType); + + const createBaz = canonicalizer.canonicalize(Baz, { + visibility: Visibility.Create, + }) as ModelHttpCanonicalization; + + expect(createBaz.properties.get("foo")!.type === createFoo).toBe(true); +}); + +it("orders canonicalizations in an SCC set", async () => { + const runner = await Tester.createInstance(); + const { ApiKey, Animal, BaseModel, DerivedModel, Dog, Cat, Wrapper, AnimalUnion, program } = + await runner.compile(t.code` + scalar ${t.scalar("ApiKey")} extends string; + + @discriminator("kind") + model ${t.model("Animal")} { + kind: string; + } + + model ${t.model("Dog")} extends Animal { + kind: "Dog"; + } + + model ${t.model("Cat")} extends Animal { + kind: "Cat"; + } + + model ${t.model("BaseModel")} { + shared: ApiKey; + } + + model ${t.model("DerivedModel")} extends BaseModel { + derived: string; + } + + model ${t.model("Wrapper")} extends DerivedModel { + pet: Animal; + } + + union ${t.union("AnimalUnion")} { + dog: Dog, + cat: Cat, + } + `); + + const tk = $(program); + const canonicalizer = new HttpCanonicalizer(tk); + const options = new HttpCanonicalizationOptions({ + visibility: Visibility.Read, + contentType: "application/json", + }); + + const apiKey = canonicalizer.canonicalize(ApiKey, options) as ScalarHttpCanonicalization; + const baseModel = canonicalizer.canonicalize(BaseModel, options) as ModelHttpCanonicalization; + const derivedModel = canonicalizer.canonicalize( + DerivedModel, + options, + ) as ModelHttpCanonicalization; + const wrapper = canonicalizer.canonicalize(Wrapper, options) as ModelHttpCanonicalization; + const animal = canonicalizer.canonicalize(Animal, options) as ModelHttpCanonicalization; + const dogModel = canonicalizer.canonicalize(Dog, options) as ModelHttpCanonicalization; + const catModel = canonicalizer.canonicalize(Cat, options) as ModelHttpCanonicalization; + const union = canonicalizer.canonicalize(AnimalUnion, options) as UnionHttpCanonicalization; + + const set = new SCCSet(httpCanonicalizationDependencyConnector); + set.addAll([apiKey, baseModel, derivedModel, wrapper, animal, dogModel, catModel, union]); + + const indexOf = (value: HttpCanonicalization) => { + expect(value).toBeDefined(); + const idx = set.items.indexOf(value); + expect(idx).toBeGreaterThanOrEqual(0); + return idx; + }; + + const expectBefore = (dependency: HttpCanonicalization, dependent: HttpCanonicalization) => { + expect(dependency).toBeDefined(); + expect(dependent).toBeDefined(); + expect(indexOf(dependency)).toBeLessThan(indexOf(dependent)); + }; + + expectBefore(baseModel, derivedModel); + expectBefore(derivedModel, wrapper); + expectBefore(dogModel, union); + expectBefore(catModel, union); +}); + +it("detects identity codec subgraphs", async () => { + const runner = await Tester.createInstance(); + const { Foo, program } = await runner.compile(t.code` + model ${t.model("Foo")} { + name: string; + } + `); + + const canonicalizer = new HttpCanonicalizer($(program)); + const options = new HttpCanonicalizationOptions({ + visibility: Visibility.Read, + contentType: "application/json", + }); + + const foo = canonicalizer.canonicalize(Foo, options); + + expect(canonicalizer.subgraphUsesIdentityCodec(foo)).toBe(true); + expect(foo.subgraphUsesIdentityCodec()).toBe(true); +}); + +it("detects non-identity codec subgraphs", async () => { + const runner = await Tester.createInstance(); + const { Foo, program } = await runner.compile(t.code` + model ${t.model("Foo")} { + createdAt: utcDateTime; + } + `); + + const canonicalizer = new HttpCanonicalizer($(program)); + const options = new HttpCanonicalizationOptions({ + visibility: Visibility.Read, + contentType: "application/json", + }); + + const foo = canonicalizer.canonicalize(Foo, options); + expect(canonicalizer.subgraphUsesIdentityCodec(foo)).toBe(false); + expect(foo.subgraphUsesIdentityCodec()).toBe(false); +}); + +it("propagates non-identity codecs to dependent components", async () => { + const runner = await Tester.createInstance(); + const { Wrapper, program } = await runner.compile(t.code` + model ${t.model("Plain")} { + name: string; + } + + model ${t.model("Encoded")} { + @encode(DateTimeKnownEncoding.rfc7231) + createdAt: utcDateTime; + } + + model ${t.model("Wrapper")} { + plain: Plain; + encoded: Encoded; + } + `); + + const canonicalizer = new HttpCanonicalizer($(program)); + const options = new HttpCanonicalizationOptions({ + visibility: Visibility.Read, + contentType: "application/json", + }); + + const wrapper = canonicalizer.canonicalize(Wrapper, options) as ModelHttpCanonicalization; + const plain = wrapper.properties.get("plain")!.type as ModelHttpCanonicalization; + const encoded = wrapper.properties.get("encoded")!.type as ModelHttpCanonicalization; + expect(canonicalizer.subgraphUsesIdentityCodec(plain)).toBe(true); + expect(canonicalizer.subgraphUsesIdentityCodec(wrapper)).toBe(false); + expect(plain.subgraphUsesIdentityCodec()).toBe(true); + expect(encoded.subgraphUsesIdentityCodec()).toBe(false); + expect(wrapper.subgraphUsesIdentityCodec()).toBe(false); +}); + +it("marks every canonicalization in a strongly connected component as non-identity when one member is encoded", async () => { + const runner = await Tester.createInstance(); + const { NodeA, NodeB, program } = await runner.compile(t.code` + model ${t.model("NodeA")} { + nodeB: NodeB; + @encode(DateTimeKnownEncoding.rfc7231) + createdAt: utcDateTime; + } + + model ${t.model("NodeB")} { + nodeA: NodeA; + } + `); + + const canonicalizer = new HttpCanonicalizer($(program)); + const options = new HttpCanonicalizationOptions({ + visibility: Visibility.Read, + contentType: "application/json", + }); + + const nodeA = canonicalizer.canonicalize(NodeA, options) as ModelHttpCanonicalization; + const nodeB = canonicalizer.canonicalize(NodeB, options) as ModelHttpCanonicalization; + + expect(canonicalizer.subgraphUsesIdentityCodec(nodeA)).toBe(false); + expect(nodeA.subgraphUsesIdentityCodec()).toBe(false); + expect(nodeB.subgraphUsesIdentityCodec()).toBe(false); + expect(canonicalizer.subgraphUsesIdentityCodec(nodeB)).toBe(false); +}); diff --git a/packages/http-canonicalization/src/http-canonicalization.ts b/packages/http-canonicalization/src/http-canonicalization.ts index 6e221dc4404..4af32251c13 100644 --- a/packages/http-canonicalization/src/http-canonicalization.ts +++ b/packages/http-canonicalization/src/http-canonicalization.ts @@ -1,39 +1,381 @@ import type { Type } from "@typespec/compiler"; import type { Typekit } from "@typespec/compiler/typekit"; -import { MutationEngine, MutationSubgraph } from "@typespec/mutator-framework"; +import { SCCSet, type NestedArray, type SCCComponent } from "@typespec/emitter-framework"; +import { + MutationEngine, + MutationHalfEdge, + MutationNode, + type MutationInfo, +} from "@typespec/mutator-framework"; +import { + getJsonCodecRegistry, + IdentityCodec, + type Codec, + type CodecRegistry, + type EncodingInfo, +} from "./codecs.js"; import { CANONICALIZATION_CLASSES, + type HttpCanonicalization, type HttpCanonicalizationMutations, } from "./http-canonicalization-classes.js"; import { HttpCanonicalizationOptions, type HttpCanonicalizationOptionsInit } from "./options.js"; -export interface LanguageMapper { - getLanguageType(specType: Type): Type; +/** + * A predicate that tests canonicalizations in a subgraph and caches the result. + */ +export abstract class CanonicalizationPredicate { + /** + * Unique identifier for the predicate, used for caching results. + */ + abstract readonly id: string; + + /** + * Tests whether a canonicalization satisfies this predicate. + * @param canonicalization The canonicalization to test. + * @returns True if the canonicalization satisfies the predicate. + */ + abstract test(canonicalization: HttpCanonicalization): boolean; + + /** + * Cache of computed results keyed by HttpCanonicalization. + */ + readonly #cache = new WeakMap(); + + /** + * Gets the cached result for a canonicalization, if available. + */ + getCached(canonicalization: HttpCanonicalization): boolean | undefined { + return this.#cache.get(canonicalization); + } + + /** + * Sets the cached result for a canonicalization. + */ + setCached(canonicalization: HttpCanonicalization, result: boolean): void { + this.#cache.set(canonicalization, result); + } +} + +/** + * A predicate that tests whether a canonicalization uses the identity codec (no transformation). + */ +export class IdentityCodecPredicate extends CanonicalizationPredicate { + readonly id = "identity"; + + test(canonicalization: HttpCanonicalization): boolean { + const codec = canonicalization.codec; + return !codec || codec instanceof IdentityCodec || codec.id === "identity"; + } } -export const TSLanguageMapper: LanguageMapper = { - getLanguageType(specType: Type): Type { - // TypeScript emitter handles all the built-in types. - return specType; - }, -}; +/** + * Pre-built predicate for testing identity codec usage. + */ +export const identityCodecPredicate = new IdentityCodecPredicate(); + +export interface HttpCanonicalizationCommon { + /** + * Codec responsible for transforming the scalar into language and wire types. + */ + codec: Codec | null; + + /** + * Whether the source type for this type is declared in TypeSpec. + */ + isDeclaration: boolean; + + /** + * The language mutation node for this canonicalization. + */ + get languageMutationNode(): MutationNode; + + /** + * The wire mutation node for this canonicalization. + */ + get wireMutationNode(): MutationNode; + + /** + * The possibly mutated language type for this literal. + */ + get languageType(): Type; + + /** + * The possibly mutated wire type for this literal. + */ + get wireType(): Type; +} export class HttpCanonicalizer extends MutationEngine { - constructor($: Typekit) { + codecs: CodecRegistry; + + constructor($: Typekit, codecs: CodecRegistry = getJsonCodecRegistry($)) { super($, CANONICALIZATION_CLASSES); - this.registerSubgraph("language"); - this.registerSubgraph("wire"); + this.codecs = codecs; } - getLanguageSubgraph(options: HttpCanonicalizationOptions): MutationSubgraph { - return this.getMutationSubgraph(options, "language"); + canonicalize( + type: T, + options?: HttpCanonicalizationOptionsInit | HttpCanonicalizationOptions, + edge?: MutationHalfEdge, + ) { + return this.mutate( + type, + options instanceof HttpCanonicalizationOptions + ? options + : new HttpCanonicalizationOptions(options), + edge, + ); } - getWireSubgraph(options: HttpCanonicalizationOptions): MutationSubgraph { - return this.getMutationSubgraph(options, "wire"); + /** + * Tests whether the subgraph rooted at the given canonicalization satisfies + * the provided predicate. Results are cached on the predicate instance. + * + * @param canonicalization The root canonicalization to test. + * @param predicate The predicate to test against canonicalizations in the subgraph. + * @returns True if all canonicalizations in the subgraph satisfy the predicate. + */ + subgraphMatchesPredicate( + canonicalization: HttpCanonicalization, + predicate: CanonicalizationPredicate, + ): boolean { + const cached = predicate.getCached(canonicalization); + if (cached !== undefined) { + return cached; + } + + const set = new SCCSet(httpCanonicalizationDependencyConnector, { + includeReachable: true, + }); + set.add(canonicalization); + + const componentResults = new Map, boolean>(); + + for (const component of set.components) { + const members = this.#componentMembers(component); + if (members.length === 0) { + continue; + } + + const existingValue = this.#getExistingComponentResult(members, predicate); + if (existingValue !== undefined) { + componentResults.set(component, existingValue); + continue; + } + + const result = this.#evaluateComponentPredicate( + component, + members, + componentResults, + predicate, + ); + for (const member of members) { + predicate.setCached(member, result); + } + componentResults.set(component, result); + } + + return predicate.getCached(canonicalization) ?? false; + } + + /** + * Tests whether the subgraph rooted at the given canonicalization uses only + * the identity codec (no transformation). + * + * @param canonicalization The root canonicalization to test. + * @returns True if all codecs in the subgraph are identity codecs. + */ + subgraphUsesIdentityCodec(canonicalization: HttpCanonicalization): boolean { + return this.subgraphMatchesPredicate(canonicalization, identityCodecPredicate); + } + + #evaluateComponentPredicate( + component: SCCComponent, + members: HttpCanonicalization[], + componentResults: Map, boolean>, + predicate: CanonicalizationPredicate, + ): boolean { + for (const member of members) { + if (!predicate.test(member)) { + return false; + } + } + + for (const dependency of component.references) { + const dependencyValue = + componentResults.get(dependency) ?? + this.#getExistingComponentResult(this.#componentMembers(dependency), predicate); + if (dependencyValue === undefined) { + throw new Error("Dependency predicate state missing before evaluation."); + } + + if (!dependencyValue) { + return false; + } + } + + return true; + } + + #componentMembers(component: SCCComponent): HttpCanonicalization[] { + return this.#flattenComponent(component.value); + } + + #getExistingComponentResult( + members: HttpCanonicalization[], + predicate: CanonicalizationPredicate, + ): boolean | undefined { + if (members.length === 0) { + return undefined; + } + const firstValue = predicate.getCached(members[0]); + if (firstValue === undefined) { + return undefined; + } + for (const member of members) { + if (predicate.getCached(member) !== firstValue) { + throw new Error("Inconsistent predicate state detected within a component."); + } + } + return firstValue; } - canonicalize(type: T, options?: HttpCanonicalizationOptionsInit) { - return this.mutate(type, new HttpCanonicalizationOptions(options)); + #flattenComponent(value: NestedArray): HttpCanonicalization[] { + if (Array.isArray(value)) { + return (value as HttpCanonicalization[][]).flat(Infinity) as HttpCanonicalization[]; + } + return [value]; + } +} + +export interface HttpCanonicalizationInfo extends MutationInfo { + encodingInfo?: EncodingInfo; +} + +/** + * Enumerates the canonicalizations referenced by the provided HTTP canonicalization. + * This can be supplied directly to an `SCCSet` connector to keep canonicalizations + * ordered by their dependency graph. + */ +export function* httpCanonicalizationDependencyConnector( + canonicalization: HttpCanonicalization, +): IterableIterator { + switch (canonicalization.kind) { + case "Operation": { + if (canonicalization.parameters) { + yield assertDependencyDefined( + canonicalization.parameters as HttpCanonicalization | undefined, + canonicalization, + "parameters", + ); + } + if (canonicalization.returnType) { + yield assertDependencyDefined( + canonicalization.returnType as HttpCanonicalization | undefined, + canonicalization, + "returnType", + ); + } + break; + } + case "Model": { + if (canonicalization.baseModel) { + yield assertDependencyDefined( + canonicalization.baseModel as HttpCanonicalization | undefined, + canonicalization, + "baseModel", + ); + } + for (const property of canonicalization.properties.values()) { + if (!property.isVisible) { + return; + } + yield assertDependencyDefined( + property as HttpCanonicalization | undefined, + canonicalization, + "property", + ); + } + if (canonicalization.indexer && canonicalization.indexer.value) { + yield assertDependencyDefined( + canonicalization.indexer.value as HttpCanonicalization | undefined, + canonicalization, + "indexer.value", + ); + } + break; + } + case "ModelProperty": { + yield assertDependencyDefined( + canonicalization.type as HttpCanonicalization | undefined, + canonicalization, + "type", + ); + break; + } + case "Scalar": { + if (canonicalization.baseScalar) { + yield assertDependencyDefined( + canonicalization.baseScalar as HttpCanonicalization | undefined, + canonicalization, + "baseScalar", + ); + } + break; + } + case "Union": { + for (const variant of canonicalization.variants.values()) { + yield assertDependencyDefined( + variant as HttpCanonicalization | undefined, + canonicalization, + "variant", + ); + } + break; + } + case "UnionVariant": { + yield assertDependencyDefined( + canonicalization.type as HttpCanonicalization | undefined, + canonicalization, + "type", + ); + break; + } + case "Enum": { + for (const member of canonicalization.members.values()) { + yield assertDependencyDefined( + member as HttpCanonicalization | undefined, + canonicalization, + "member", + ); + } + break; + } + case "EnumMember": + case "Intrinsic": + case "Literal": + break; + default: { + const _exhaustiveCheck: never = canonicalization; + void _exhaustiveCheck; + break; + } + } +} + +function assertDependencyDefined( + dependency: HttpCanonicalization | undefined, + canonicalization: HttpCanonicalization, + path: string, +): HttpCanonicalization { + if (dependency === undefined) { + /* eslint-disable-next-line no-console */ + console.error("Undefined HTTP canonicalization dependency.", { + canonicalization, + path, + }); + throw new Error(`HTTP canonicalization dependency "${path}" resolved to undefined.`); } + return dependency; } diff --git a/packages/http-canonicalization/src/index.ts b/packages/http-canonicalization/src/index.ts index 2bc509f0afa..80e5772ba12 100644 --- a/packages/http-canonicalization/src/index.ts +++ b/packages/http-canonicalization/src/index.ts @@ -1,4 +1,6 @@ export * from "./codecs.js"; +export * from "./enum-member.js"; +export * from "./enum.js"; export * from "./http-canonicalization-classes.js"; export * from "./http-canonicalization.js"; export * from "./intrinsic.js"; diff --git a/packages/http-canonicalization/src/intrinsic.ts b/packages/http-canonicalization/src/intrinsic.ts index 7f7e488c0bc..5bbc552ecfc 100644 --- a/packages/http-canonicalization/src/intrinsic.ts +++ b/packages/http-canonicalization/src/intrinsic.ts @@ -1,52 +1,74 @@ import type { IntrinsicType, MemberType } from "@typespec/compiler"; -import { IntrinsicMutation } from "@typespec/mutator-framework"; +import { + IntrinsicMutation, + type MutationHalfEdge, + type MutationNodeForType, + type MutationTraits, +} from "@typespec/mutator-framework"; +import type { Codec } from "./codecs.js"; import type { HttpCanonicalizationMutations } from "./http-canonicalization-classes.js"; -import { HttpCanonicalizer } from "./http-canonicalization.js"; +import { + HttpCanonicalizer, + type CanonicalizationPredicate, + type HttpCanonicalizationCommon, + type HttpCanonicalizationInfo, +} from "./http-canonicalization.js"; import { HttpCanonicalizationOptions } from "./options.js"; /** * Canonicalizes intrinsic types for HTTP. */ -export class IntrinsicHttpCanonicalization extends IntrinsicMutation< - HttpCanonicalizationOptions, - HttpCanonicalizationMutations, - HttpCanonicalizer -> { - /** - * Canonicalization options. - */ - options: HttpCanonicalizationOptions; - /** - * Indicates if this intrinsic represents a named declaration. Always false. - */ - isDeclaration: boolean = false; +export class IntrinsicHttpCanonicalization + extends IntrinsicMutation< + HttpCanonicalizationOptions, + HttpCanonicalizationMutations, + HttpCanonicalizer + > + implements HttpCanonicalizationCommon +{ + isDeclaration = false; + codec: Codec | null = null; - /** - * Mutation subgraph for language types. - */ - get #languageSubgraph() { - return this.engine.getLanguageSubgraph(this.options); + #languageMutationNode: MutationNodeForType; + #wireMutationNode: MutationNodeForType; + + get languageMutationNode() { + return this.#languageMutationNode; } - /** - * Mutation subgraph for wire types. - */ - get #wireSubgraph() { - return this.engine.getWireSubgraph(this.options); + get wireMutationNode() { + return this.#wireMutationNode; } /** - * The possibly mutated language type for this intrinsic. + * Tests whether the subgraph rooted at this canonicalization uses only + * the identity codec (no transformation). */ - get languageType() { - return this.getMutatedType(this.#languageSubgraph); + subgraphUsesIdentityCodec(): boolean { + return this.engine.subgraphUsesIdentityCodec(this); } /** - * The possibly mutated wire type for this intrinsic. + * Tests whether the subgraph rooted at this canonicalization satisfies + * the provided predicate. */ - get wireType() { - return this.getMutatedType(this.#wireSubgraph); + subgraphMatchesPredicate(predicate: CanonicalizationPredicate): boolean { + return this.engine.subgraphMatchesPredicate(this, predicate); + } + + static mutationInfo( + engine: HttpCanonicalizer, + sourceType: IntrinsicType, + referenceTypes: MemberType[], + options: HttpCanonicalizationOptions, + halfEdge?: MutationHalfEdge, + traits?: MutationTraits, + ): HttpCanonicalizationInfo { + return { + mutationKey: options.mutationKey, + codec: null as any, // Intrinsics don't need a codec + isSynthetic: traits?.isSynthetic, + }; } constructor( @@ -54,8 +76,30 @@ export class IntrinsicHttpCanonicalization extends IntrinsicMutation< sourceType: IntrinsicType, referenceTypes: MemberType[], options: HttpCanonicalizationOptions, + info: HttpCanonicalizationInfo, ) { - super(engine, sourceType, referenceTypes, options); - this.options = options; + super(engine, sourceType, referenceTypes, options, info); + this.#languageMutationNode = this.engine.getMutationNode( + this.sourceType, + info.mutationKey + "-language", + ); + this.#wireMutationNode = this.engine.getMutationNode( + this.sourceType, + info.mutationKey + "-wire", + ); + } + + /** + * The possibly mutated language type for this intrinsic. + */ + get languageType() { + return this.#languageMutationNode.mutatedType; + } + + /** + * The possibly mutated wire type for this intrinsic. + */ + get wireType() { + return this.#wireMutationNode.mutatedType; } } diff --git a/packages/http-canonicalization/src/literal.ts b/packages/http-canonicalization/src/literal.ts index a7b3d827cd1..4301dcdd0e3 100644 --- a/packages/http-canonicalization/src/literal.ts +++ b/packages/http-canonicalization/src/literal.ts @@ -1,53 +1,82 @@ import type { BooleanLiteral, MemberType, NumericLiteral, StringLiteral } from "@typespec/compiler"; -import { LiteralMutation } from "@typespec/mutator-framework"; +import { + LiteralMutation, + type MutationHalfEdge, + type MutationNodeForType, + type MutationTraits, +} from "@typespec/mutator-framework"; +import type { Codec } from "./codecs.js"; import type { HttpCanonicalizationMutations } from "./http-canonicalization-classes.js"; -import type { HttpCanonicalizer } from "./http-canonicalization.js"; +import type { + CanonicalizationPredicate, + HttpCanonicalizationCommon, + HttpCanonicalizationInfo, + HttpCanonicalizer, +} from "./http-canonicalization.js"; import { HttpCanonicalizationOptions } from "./options.js"; /** * Canonicalizes literal types for HTTP. */ -export class LiteralHttpCanonicalization extends LiteralMutation< - HttpCanonicalizationOptions, - HttpCanonicalizationMutations, - HttpCanonicalizer -> { - /** - * Canonicalization options. - */ - options: HttpCanonicalizationOptions; - /** - * Indicates if the literal is defined as a named TypeSpec declaration. Always - * false for literals. - */ - isDeclaration: boolean = false; +export class LiteralHttpCanonicalization + extends LiteralMutation< + HttpCanonicalizationOptions, + HttpCanonicalizationMutations, + HttpCanonicalizer + > + implements HttpCanonicalizationCommon +{ + isDeclaration = false; + codec: Codec | null = null; - /** - * Mutation subgraph for language types. - */ - get #languageSubgraph() { - return this.engine.getLanguageSubgraph(this.options); + #languageMutationNode: MutationNodeForType; + #wireMutationNode: MutationNodeForType; + + get languageMutationNode() { + return this.#languageMutationNode; } - /** - * Mutation subgraph for wire types. - */ - get #wireSubgraph() { - return this.engine.getWireSubgraph(this.options); + get wireMutationNode() { + return this.#wireMutationNode; + } + + get languageType() { + return this.#languageMutationNode.mutatedType; + } + + get wireType() { + return this.#wireMutationNode.mutatedType; } /** - * The possibly mutated language type for this literal. + * Tests whether the subgraph rooted at this canonicalization uses only + * the identity codec (no transformation). */ - get languageType() { - return this.getMutatedType(this.#languageSubgraph); + subgraphUsesIdentityCodec(): boolean { + return this.engine.subgraphUsesIdentityCodec(this); } /** - * The possibly mutated wire type for this literal. + * Tests whether the subgraph rooted at this canonicalization satisfies + * the provided predicate. */ - get wireType() { - return this.getMutatedType(this.#wireSubgraph); + subgraphMatchesPredicate(predicate: CanonicalizationPredicate): boolean { + return this.engine.subgraphMatchesPredicate(this, predicate); + } + + static mutationInfo( + engine: HttpCanonicalizer, + sourceType: StringLiteral | NumericLiteral | BooleanLiteral, + referenceTypes: MemberType[], + options: HttpCanonicalizationOptions, + halfEdge?: MutationHalfEdge, + traits?: MutationTraits, + ): HttpCanonicalizationInfo { + return { + mutationKey: options.mutationKey, + codec: null as any, // Literals don't need a codec + isSynthetic: traits?.isSynthetic, + }; } constructor( @@ -55,8 +84,17 @@ export class LiteralHttpCanonicalization extends LiteralMutation< sourceType: StringLiteral | NumericLiteral | BooleanLiteral, referenceTypes: MemberType[], options: HttpCanonicalizationOptions, + info: HttpCanonicalizationInfo, ) { - super(engine, sourceType, referenceTypes, options); + super(engine, sourceType, referenceTypes, options, info); this.options = options; + this.#languageMutationNode = this.engine.getMutationNode( + this.sourceType, + info.mutationKey + "-language", + ); + this.#wireMutationNode = this.engine.getMutationNode( + this.sourceType, + info.mutationKey + "-wire", + ); } } diff --git a/packages/http-canonicalization/src/model-property.test.ts b/packages/http-canonicalization/src/model-property.test.ts index 8f808115f6d..091a0471e6f 100644 --- a/packages/http-canonicalization/src/model-property.test.ts +++ b/packages/http-canonicalization/src/model-property.test.ts @@ -1,17 +1,64 @@ -import { t, type TesterInstance } from "@typespec/compiler/testing"; +import { expectTypeEquals, t, type TesterInstance } from "@typespec/compiler/testing"; import { $ } from "@typespec/compiler/typekit"; import { Visibility } from "@typespec/http"; import { beforeEach, expect, it } from "vitest"; import { Tester } from "../test/test-host.js"; +import { + ArrayJoinCodec, + Base64Codec, + CodecRegistry, + CoerceToFloat64Codec, + IdentityCodec, + RenameCodec, + Rfc3339Codec, + Rfc7231Codec, + UnixTimestamp32Codec, + UnixTimestamp64Codec, +} from "./codecs.js"; import { HttpCanonicalizer } from "./http-canonicalization.js"; +import type { ScalarHttpCanonicalization } from "./scalar.js"; let runner: TesterInstance; beforeEach(async () => { runner = await Tester.createInstance(); }); -// skip, haven't implemented metadata stuff yet -it.skip("removes metadata properties from wire type", async () => { +it("canonicalizes properties with encoding differently than the referenced type", async () => { + const { Foo, program } = await runner.compile(t.code` + model ${t.model("Foo")} { + @encode(DateTimeKnownEncoding.rfc7231) + ${t.modelProperty("one")}: utcDateTime; + + @encode(DateTimeKnownEncoding.rfc3339) + ${t.modelProperty("two")}: utcDateTime; + } + `); + + const tk = $(program); + + const canonicalizer = new HttpCanonicalizer(tk); + const canonicalized = canonicalizer.canonicalize(Foo, { + visibility: Visibility.Read, + contentType: "application/json", + }); + + const one = canonicalized.properties.get("one")!; + const two = canonicalized.properties.get("two")!; + + expectTypeEquals(one.languageType.type, tk.builtin.utcDateTime); + expectTypeEquals(one.wireType.type, tk.builtin.string); + + expectTypeEquals(two.languageType.type, tk.builtin.utcDateTime); + expectTypeEquals(two.wireType.type, tk.builtin.string); + + const oneType = one.type as ScalarHttpCanonicalization; + const twoType = two.type as ScalarHttpCanonicalization; + + expect(oneType.codec.id).toBe("rfc7231"); + expect(twoType.codec.id).toBe("rfc3339"); +}); + +it("removes metadata properties from wire type", async () => { const { Foo, program } = await runner.compile(t.code` model ${t.model("Foo")} { @visibility(Lifecycle.Read) @@ -31,3 +78,84 @@ it.skip("removes metadata properties from wire type", async () => { expect(write.languageType.properties.has("etag")).toBe(true); expect(write.wireType.properties.has("etag")).toBe(false); }); + +it("makes nullable properties optional on the wire", async () => { + const { Foo, program } = await runner.compile(t.code` + model ${t.model("Foo")} { + id: string | null; + } + `); + + const tk = $(program); + + const canonicalizer = new HttpCanonicalizer(tk); + const foo = canonicalizer.canonicalize(Foo, { + visibility: Visibility.Read, + contentType: "application/json", + }); + const prop = foo.properties.get("id")!; + expect(prop.typeIsNullable).toBe(true); + + const langType = prop.languageType; + expect(langType.optional).toBe(false); + + const wireType = prop.wireType; + expect(wireType.optional).toBe(true); +}); + +it("applies friendly name", async () => { + const { Foo, program } = await runner.compile(t.code` + model ${t.model("Foo")} { + @friendlyName("FooId") + id: string | null; + } + `); + + const tk = $(program); + + const canonicalizer = new HttpCanonicalizer(tk); + const foo = canonicalizer.canonicalize(Foo, { + visibility: Visibility.Read, + contentType: "application/json", + }); + + const prop = foo.properties.get("id")!; + expect(prop).toBeDefined(); + expect(prop.languageType.name).toBe("FooId"); + expect(prop.wireType.name).toBe("id"); +}); + +it("Applies renames", async () => { + const { program, test } = await runner.compile(t.code` + op ${t.op("test")}(): Foo; + + model ${t.model("Foo")} { + rename_thing: string; + } + `); + + const tk = $(program); + const codecs = new CodecRegistry(tk); + codecs.addCodec(new CoerceToFloat64Codec()); + codecs.addCodec(new Rfc7231Codec()); + codecs.addCodec(new UnixTimestamp32Codec()); + codecs.addCodec(new UnixTimestamp64Codec()); + codecs.addCodec(new Rfc3339Codec()); + codecs.addCodec(new Base64Codec()); + codecs.addCodec(new Base64Codec()); + codecs.addCodec(new ArrayJoinCodec()); + codecs.addCodec( + new RenameCodec({ + namer(type) { + return (type as any).name + "Renamed"; + }, + }), + ); + codecs.addCodec(new IdentityCodec()); + const canonicalizer = new HttpCanonicalizer(tk, codecs); + + const canonTest = canonicalizer.canonicalize(test); + const model = (canonTest as any).responses[0].responses[0].body.bodies[0].type; + expect(model.languageType.properties.size).toBe(1); + expect(model.languageType.properties.has("rename_thingRenamed")).toBe(true); +}); diff --git a/packages/http-canonicalization/src/model-property.ts b/packages/http-canonicalization/src/model-property.ts index 56bc9ebefaa..21a48219563 100644 --- a/packages/http-canonicalization/src/model-property.ts +++ b/packages/http-canonicalization/src/model-property.ts @@ -1,37 +1,50 @@ import type { MemberType, ModelProperty } from "@typespec/compiler"; -import { getHeaderFieldOptions, getQueryParamOptions, isVisible } from "@typespec/http"; -import { ModelPropertyMutation } from "@typespec/mutator-framework"; -import { Codec, getJsonEncoderRegistry } from "./codecs.js"; +import { + getHeaderFieldOptions, + getPathParamOptions, + getQueryParamOptions, + isBody, + isBodyRoot, + isMetadata, + isVisible, +} from "@typespec/http"; +import { + ModelPropertyMutation, + MutationHalfEdge, + type MutationNodeForType, + type MutationTraits, +} from "@typespec/mutator-framework"; +import type { Codec, EncodingInfo } from "./codecs.js"; +import type { HttpCanonicalizationMutations } from "./http-canonicalization-classes.js"; import type { - HttpCanonicalization, - HttpCanonicalizationMutations, -} from "./http-canonicalization-classes.js"; -import type { HttpCanonicalizer } from "./http-canonicalization.js"; + CanonicalizationPredicate, + HttpCanonicalizationCommon, + HttpCanonicalizationInfo, + HttpCanonicalizer, +} from "./http-canonicalization.js"; import { HttpCanonicalizationOptions } from "./options.js"; /** * Canonicalizes model properties, tracking request/response metadata and visibility. */ -export class ModelPropertyHttpCanonicalization extends ModelPropertyMutation< - HttpCanonicalizationOptions, - HttpCanonicalizationMutations, - HttpCanonicalizer -> { - /** - * Indicates if this property corresponds to a named declaration. Always - * false. - */ - isDeclaration: boolean = false; +export class ModelPropertyHttpCanonicalization + extends ModelPropertyMutation< + HttpCanonicalizationMutations, + HttpCanonicalizationOptions, + HttpCanonicalizer + > + implements HttpCanonicalizationCommon +{ + isDeclaration = false; /** * Whether the property is visible given the current visibility options. */ isVisible: boolean = false; - /** - * Codec used to transform the property's type between language and wire views. - */ - codec: Codec; + codec: Codec | null = null; + + #encodingInfo: EncodingInfo | null = null; /** * True when the property is a query parameter. @@ -53,6 +66,11 @@ export class ModelPropertyHttpCanonicalization extends ModelPropertyMutation< */ headerName: string = ""; + /** + * Whether the property is metadata (i.e. not part of an HTTP body). + */ + isMetadata: boolean = false; + /** * True when the property is a path parameter. */ @@ -69,31 +87,83 @@ export class ModelPropertyHttpCanonicalization extends ModelPropertyMutation< explode: boolean = false; /** - * Mutation subgraph for language types. + * Whether this is the property which declares the HTTP content type. */ - get #languageSubgraph() { - return this.engine.getLanguageSubgraph(this.options); - } + isContentTypeProperty: boolean = false; /** - * Mutation subgraph for wire types. + * Whether this is the property which declares the HTTP body. */ - get #wireSubgraph() { - return this.engine.getWireSubgraph(this.options); + isBodyProperty: boolean = false; + + #languageMutationNode: MutationNodeForType; + get languageMutationNode() { + return this.#languageMutationNode; + } + + #wireMutationNode: MutationNodeForType; + get wireMutationNode() { + return this.#wireMutationNode; } /** * The possibly mutated language type for this property. */ get languageType() { - return this.getMutatedType(this.#languageSubgraph); + return this.#languageMutationNode.mutatedType; } /** * The possibly mutated wire type for this property. */ get wireType() { - return this.getMutatedType(this.#wireSubgraph); + return this.#wireMutationNode.mutatedType; + } + + /** + * Tests whether the subgraph rooted at this canonicalization uses only + * the identity codec (no transformation). + */ + subgraphUsesIdentityCodec(): boolean { + return this.engine.subgraphUsesIdentityCodec(this); + } + + /** + * Tests whether the subgraph rooted at this canonicalization satisfies + * the provided predicate. + */ + subgraphMatchesPredicate(predicate: CanonicalizationPredicate): boolean { + return this.engine.subgraphMatchesPredicate(this, predicate); + } + + /** + * Whether the type of this property is a nullable union. For the JSON content + * type, nullable properties are optional on the wire. + */ + typeIsNullable: boolean = false; + + protected startTypeEdge() { + return new MutationHalfEdge("type", this, (tail) => { + this.#languageMutationNode.connectType(tail.languageMutationNode); + this.#wireMutationNode.connectType(tail.wireMutationNode); + }); + } + + static mutationInfo( + engine: HttpCanonicalizer, + sourceType: ModelProperty, + referenceTypes: MemberType[], + options: HttpCanonicalizationOptions, + halfEdge?: MutationHalfEdge, + traits?: MutationTraits, + ): HttpCanonicalizationInfo { + const encodingInfo = engine.codecs.encode(sourceType, referenceTypes); + + return { + mutationKey: options.mutationKey, + encodingInfo, + isSynthetic: traits?.isSynthetic, + }; } constructor( @@ -101,8 +171,18 @@ export class ModelPropertyHttpCanonicalization extends ModelPropertyMutation< sourceType: ModelProperty, referenceTypes: MemberType[], options: HttpCanonicalizationOptions, + info: HttpCanonicalizationInfo, ) { - super(engine, sourceType, referenceTypes, options); + super(engine, sourceType, referenceTypes, options, info); + this.#languageMutationNode = this.engine.getMutationNode( + this.sourceType, + info.mutationKey + "-language", + ); + this.#wireMutationNode = this.engine.getMutationNode( + this.sourceType, + info.mutationKey + "-wire", + ); + this.isDeclaration = !!this.sourceType.name; this.isVisible = isVisible(this.engine.$.program, this.sourceType, this.options.visibility); const headerInfo = getHeaderFieldOptions(this.engine.$.program, this.sourceType); @@ -118,7 +198,7 @@ export class ModelPropertyHttpCanonicalization extends ModelPropertyMutation< this.queryParameterName = queryInfo.name; this.explode = !!queryInfo.explode; } else { - const pathInfo = getQueryParamOptions(this.engine.$.program, this.sourceType); + const pathInfo = getPathParamOptions(this.engine.$.program, this.sourceType); if (pathInfo) { this.isPathParameter = true; this.pathParameterName = pathInfo.name; @@ -127,23 +207,41 @@ export class ModelPropertyHttpCanonicalization extends ModelPropertyMutation< } } - const registry = getJsonEncoderRegistry(this.engine.$); - this.codec = registry.detect(this); + this.isMetadata = isMetadata(this.engine.$.program, this.sourceType); + this.isBodyProperty = + isBody(this.engine.$.program, this.sourceType) || + isBodyRoot(this.engine.$.program, this.sourceType); + + this.isContentTypeProperty = this.isHeader && this.headerName.toLowerCase() === "content-type"; + + if ( + this.engine.$.union.is(this.sourceType.type) && + this.options.contentType === "application/json" + ) { + const variants = [...this.sourceType.type.variants.values()]; + if (variants.some((v) => v.type === this.engine.$.intrinsic.null)) { + this.typeIsNullable = true; + } + } + + this.codec = info.encodingInfo?.codec ?? null; + this.#encodingInfo = info.encodingInfo ?? null; } /** * Apply HTTP canonicalization. */ mutate() { - const languageNode = this.getMutationNode(this.#languageSubgraph); - const wireNode = this.getMutationNode(this.#wireSubgraph); - if (!this.isVisible) { - languageNode.delete(); - wireNode.delete(); + this.#languageMutationNode.delete(); + this.#wireMutationNode.delete(); return; } + if (this.isMetadata) { + this.#wireMutationNode.delete(); + } + const newOptions = this.isHeader ? this.options.with({ location: `header${this.explode ? "-explode" : ""}`, @@ -158,6 +256,27 @@ export class ModelPropertyHttpCanonicalization extends ModelPropertyMutation< }) : this.options.with({ location: "body" }); - this.type = this.engine.mutateReference(this.sourceType, newOptions) as HttpCanonicalization; + if (this.typeIsNullable) { + // nullable things often mean optional things, I guess. + this.#wireMutationNode.mutate((prop) => { + prop.optional = true; + }); + } + + if (this.#encodingInfo) { + const { languageType, wireType } = this.#encodingInfo; + if (languageType !== this.sourceType) { + this.#languageMutationNode = this.#languageMutationNode.replace( + languageType as ModelProperty, + ) as MutationNodeForType; + } + if (wireType !== this.sourceType) { + this.#wireMutationNode = this.#wireMutationNode.replace( + wireType as ModelProperty, + ) as MutationNodeForType; + } + } + + super.mutate(newOptions); } } diff --git a/packages/http-canonicalization/src/model.test.ts b/packages/http-canonicalization/src/model.test.ts new file mode 100644 index 00000000000..fdbb0e28cca --- /dev/null +++ b/packages/http-canonicalization/src/model.test.ts @@ -0,0 +1,141 @@ +import { t, type TesterInstance } from "@typespec/compiler/testing"; +import { $ } from "@typespec/compiler/typekit"; +import { Visibility } from "@typespec/http"; +import { beforeEach, expect, it } from "vitest"; +import { Tester } from "../test/test-host.js"; +import type { HttpCanonicalization } from "./http-canonicalization-classes.js"; +import { HttpCanonicalizer } from "./http-canonicalization.js"; +import type { ModelHttpCanonicalization } from "./model.js"; + +let runner: TesterInstance; +beforeEach(async () => { + runner = await Tester.createInstance(); +}); + +it("applies friendly name", async () => { + const { Foo, program } = await runner.compile(t.code` + @friendlyName("Bar") + model ${t.model("Foo")} { + } + `); + + const tk = $(program); + + const canonicalizer = new HttpCanonicalizer(tk); + const canonicalized = canonicalizer.canonicalize(Foo, { + visibility: Visibility.Read, + }); + + expect(canonicalized.languageType.name).toBe("Bar"); + expect(canonicalized.wireType.name).toBe("Bar"); +}); + +it("works for polymorphic models", async () => { + const { Animal, Test, program } = await runner.compile(t.code` + @discriminator("kind") + model ${t.model("Animal")} { + kind: string; + } + + model Dog extends Animal { + kind: "Dog"; + } + + model Cat extends Animal { + kind: "Cat"; + } + + model ${t.model("Test")} { + prop: Animal; + } + `); + + const tk = $(program); + + const canonicalizer = new HttpCanonicalizer(tk); + const canonicalized = canonicalizer.canonicalize(Animal, { + visibility: Visibility.Read, + contentType: "application/json", + }); + + expect(canonicalized.isPolymorphicModel).toBe(true); + + const union = canonicalized.polymorphicModelUnion!; + expect(union.variants.size).toBe(2); + const info = tk.union.getDiscriminatedUnion(union.languageType); + expect(info!.options).toEqual({ + envelope: "none", + discriminatorPropertyName: "kind", + envelopePropertyName: "value", + }); + expect(canonicalized.languageMutationNode.kind === "Model").toBe(true); + + // verify that the Test model's prop property points to the union + const testCanonicalized = canonicalizer.canonicalize(Test, { + visibility: Visibility.Read, + contentType: "application/json", + }); + const propType = testCanonicalized.properties.get("prop")!.type as HttpCanonicalization; + expect(propType.kind === "Union").toBe(true); +}); + +it("works for polymorphic models that are referenced in arrays", async () => { + const { Test, program } = await runner.compile(t.code` + @discriminator("kind") + model ${t.model("Animal")} { + kind: string; + } + + model Dog extends Animal { + kind: "Dog"; + } + + model Cat extends Animal { + kind: "Cat"; + } + + model ${t.model("Test")} { + prop: Animal[]; + } + `); + + const tk = $(program); + + const canonicalizer = new HttpCanonicalizer(tk); + // verify that the Test model's prop property points to the union + const testCanonicalized = canonicalizer.canonicalize(Test, { + visibility: Visibility.Read, + contentType: "application/json", + }); + const propType = testCanonicalized.properties.get("prop")!.type as ModelHttpCanonicalization; + expect(propType.kind).toBe("Model"); + const indexerType = propType.indexer?.value as HttpCanonicalization; + expect(indexerType.kind).toBe("Union"); +}); + +it("uses effective models", async () => { + const { Animal, Test, program } = await runner.compile(t.code` + model ${t.model("Animal")} { + kind: string; + } + + model ${t.model("Test")} { + prop: { ... Animal }; + } + `); + + const tk = $(program); + + const canonicalizer = new HttpCanonicalizer(tk); + // verify that the Test model's prop property points to the union + const testCanonicalized = canonicalizer.canonicalize(Test, { + visibility: Visibility.Read, + contentType: "application/json", + }); + const animalCanonicalized = canonicalizer.canonicalize(Animal, { + visibility: Visibility.Read, + contentType: "application/json", + }); + const propType = testCanonicalized.properties.get("prop")!.type as ModelHttpCanonicalization; + expect(propType === animalCanonicalized).toBe(true); +}); diff --git a/packages/http-canonicalization/src/model.ts b/packages/http-canonicalization/src/model.ts index e43d3228ec4..f1da99c2fec 100644 --- a/packages/http-canonicalization/src/model.ts +++ b/packages/http-canonicalization/src/model.ts @@ -1,57 +1,156 @@ -import type { MemberType, Model } from "@typespec/compiler"; +import { + discriminatedDecorator, + getDiscriminator, + getFriendlyName, + type MemberType, + type Model, + type Union, +} from "@typespec/compiler"; +import type { Typekit } from "@typespec/compiler/typekit"; import { getVisibilitySuffix, Visibility } from "@typespec/http"; -import { ModelMutation } from "@typespec/mutator-framework"; -import { Codec, getJsonEncoderRegistry } from "./codecs.js"; +import { + ModelMutation, + MutationHalfEdge, + type MutationNodeForType, + type MutationTraits, +} from "@typespec/mutator-framework"; +import { Codec } from "./codecs.js"; import type { HttpCanonicalizationMutations } from "./http-canonicalization-classes.js"; -import type { HttpCanonicalizer } from "./http-canonicalization.js"; +import type { + CanonicalizationPredicate, + HttpCanonicalizationCommon, + HttpCanonicalizationInfo, + HttpCanonicalizer, +} from "./http-canonicalization.js"; import type { ModelPropertyHttpCanonicalization } from "./model-property.js"; import { HttpCanonicalizationOptions } from "./options.js"; -import type { ScalarHttpCanonicalization } from "./scalar.js"; +import type { UnionHttpCanonicalization } from "./union.js"; +const polymorphicUnionCache = new WeakMap(); +function getUnionForPolymorphicModel($: Typekit, model: Model) { + if (polymorphicUnionCache.has(model)) { + return polymorphicUnionCache.get(model)!; + } + + const unionInfo = $.model.getDiscriminatedUnion(model)!; + + const union = $.union.create({ + name: model.name + "Union", + decorators: [ + [ + discriminatedDecorator, + { envelope: "none", discriminatorPropertyName: unionInfo.propertyName }, + ], + ], + variants: [...unionInfo.variants].map(([name, type]) => { + return $.unionVariant.create({ name, type }); + }), + }); + + polymorphicUnionCache.set(model, union); + return union; +} /** * Canonicalizes models for HTTP. */ -export class ModelHttpCanonicalization extends ModelMutation< - HttpCanonicalizationOptions, - HttpCanonicalizationMutations, - HttpCanonicalizer -> { - /** - * Indicates if the canonicalization wraps a named TypeSpec declaration. - */ - isDeclaration: boolean = false; +export class ModelHttpCanonicalization + extends ModelMutation< + HttpCanonicalizationMutations, + HttpCanonicalizationOptions, + HttpCanonicalizer + > + implements HttpCanonicalizationCommon +{ + isDeclaration = false; + codec: Codec | null = null; + + #languageMutationNode: MutationNodeForType; + get languageMutationNode() { + return this.#languageMutationNode; + } + + #wireMutationNode: MutationNodeForType; + get wireMutationNode() { + return this.#wireMutationNode; + } + + get languageType() { + return this.#languageMutationNode.mutatedType; + } + + get wireType() { + return this.#wireMutationNode.mutatedType; + } /** - * Codec chosen to transform language and wire types for this model. + * Whether this this model is a polymorphic model, i.e. has the @discriminator + * decorator on it. Such models are essentially unions of all their subtypes. */ - codec: Codec; + isPolymorphicModel: boolean = false; /** - * Mutation subgraph for language types. + * When this model is a polymorphic model, a discriminated union type of all + * the subtypes of the model. */ - get #languageSubgraph() { - return this.engine.getLanguageSubgraph(this.options); - } + polymorphicModelUnion: UnionHttpCanonicalization | null = null; /** - * Mutation subgraph for wire types. + * Tests whether the subgraph rooted at this canonicalization uses only + * the identity codec (no transformation). */ - get #wireSubgraph() { - return this.engine.getWireSubgraph(this.options); + subgraphUsesIdentityCodec(): boolean { + return this.engine.subgraphUsesIdentityCodec(this); } /** - * The possibly mutated language type for this model. + * Tests whether the subgraph rooted at this canonicalization satisfies + * the provided predicate. */ - get languageType() { - return this.getMutatedType(this.#languageSubgraph); + subgraphMatchesPredicate(predicate: CanonicalizationPredicate): boolean { + return this.engine.subgraphMatchesPredicate(this, predicate); } - /** - * The possibly mutated wire type for this model. - */ - get wireType() { - return this.getMutatedType(this.#wireSubgraph); + static mutationInfo( + engine: HttpCanonicalizer, + sourceType: Model, + referenceTypes: MemberType[], + options: HttpCanonicalizationOptions, + halfEdge?: MutationHalfEdge, + traits?: MutationTraits, + ): HttpCanonicalizationInfo | UnionHttpCanonicalization | ModelHttpCanonicalization { + // Models don't directly use codecs, they're used on their properties + const isDiscriminated = !!getDiscriminator(engine.$.program, sourceType); + if (halfEdge?.head !== undefined && halfEdge.kind !== "base" && isDiscriminated) { + // If we aren't the base of another model, we are the union. + + const union = getUnionForPolymorphicModel(engine.$, sourceType); + if (referenceTypes.length === 0) { + return engine.mutate(union, options, halfEdge, { isSynthetic: true }); + } else { + return engine.replaceAndMutateReference(referenceTypes[0], union, options, halfEdge); + } + } + + const effectiveModel = engine.$.model.getEffectiveModel(sourceType); + if (effectiveModel !== sourceType) { + // If this model is an alias, we just forward to the effective model + if (referenceTypes.length === 0) { + return engine.mutate(effectiveModel, options, halfEdge); + } else { + return engine.replaceAndMutateReference( + referenceTypes[0], + effectiveModel, + options, + halfEdge, + ); + } + } + + return { + mutationKey: options.mutationKey, + isPolymorphicModel: isDiscriminated, + isSynthetic: traits?.isSynthetic, + }; } constructor( @@ -59,11 +158,21 @@ export class ModelHttpCanonicalization extends ModelMutation< sourceType: Model, referenceTypes: MemberType[], options: HttpCanonicalizationOptions, + info: HttpCanonicalizationInfo, + traits: MutationTraits, ) { - super(engine, sourceType, referenceTypes, options); + super(engine, sourceType, referenceTypes, options, info); this.isDeclaration = !!this.sourceType.name; - const registry = getJsonEncoderRegistry(this.engine.$); - this.codec = registry.detect(this); + this.#languageMutationNode = this.engine.getMutationNode(this.sourceType, { + mutationKey: info.mutationKey + "-language", + isSynthetic: info.isSynthetic, + }); + this.#wireMutationNode = this.engine.getMutationNode(this.sourceType, { + mutationKey: info.mutationKey + "-wire", + isSynthetic: info.isSynthetic, + }); + + this.isPolymorphicModel = !!info.isPolymorphicModel; } /** @@ -78,48 +187,68 @@ export class ModelHttpCanonicalization extends ModelMutation< ); } - /** - * Applies mutations required to build the language and wire views of the model. - */ mutate() { - const languageNode = this.getMutationNode(this.engine.getLanguageSubgraph(this.options)); - languageNode.whenMutated(this.#renameWhenMutated.bind(this)); + if (this.isPolymorphicModel) { + this.polymorphicModelUnion = this.engine.canonicalize( + getUnionForPolymorphicModel(this.engine.$, this.sourceType), + this.options, + ); + } + // fix up merge patch update graph node + if (this.sourceType.name === "MergePatchUpdate" && this.sourceType.properties.size > 0) { + const firstProp = this.sourceType.properties.values().next().value!; + const model = firstProp.model!; - const wireNode = this.getMutationNode(this.engine.getWireSubgraph(this.options)); - wireNode.whenMutated(this.#renameWhenMutated.bind(this)); + this.#languageMutationNode = this.#languageMutationNode.replace( + this.engine.$.type.clone(model), + ) as any; + this.#wireMutationNode = this.#wireMutationNode.replace( + this.engine.$.type.clone(model), + ) as any; + } - if (this.engine.$.array.is(this.sourceType) && this.sourceType.name === "Array") { - if (this.sourceType.baseModel) { - this.baseModel = this.engine.mutate(this.sourceType.baseModel, this.options); - } + const friendlyName = getFriendlyName(this.engine.$.program, this.sourceType); + if (friendlyName) { + this.#languageMutationNode.mutate((type) => { + type.name = friendlyName; + }); + this.#wireMutationNode.mutate((type) => (type.name = friendlyName)); + } else { + this.#languageMutationNode.whenMutated(this.#renameWhenMutated.bind(this)); + this.#wireMutationNode.whenMutated(this.#renameWhenMutated.bind(this)); + } - for (const prop of this.sourceType.properties.values()) { - this.properties.set(prop.name, this.engine.mutate(prop, this.options)); - } + super.mutateBaseModel(); + super.mutateProperties(); + super.mutateIndexer(); + } - const newIndexerOptions: Partial = { - visibility: this.options.visibility | Visibility.Item, - }; + protected startBaseEdge(): MutationHalfEdge { + return new MutationHalfEdge("base", this, (tail) => { + this.#languageMutationNode.connectBase(tail.languageMutationNode); + this.#wireMutationNode.connectBase(tail.wireMutationNode); + }); + } - if (this.options.isJsonMergePatch()) { - newIndexerOptions.contentType = "application/json"; - } + protected startPropertyEdge(): MutationHalfEdge { + return new MutationHalfEdge("property", this, (tail) => { + this.#languageMutationNode.connectProperty(tail.languageMutationNode); + this.#wireMutationNode.connectProperty(tail.wireMutationNode); + }); + } - this.indexer = { - key: this.engine.mutate( - this.sourceType.indexer.key, - this.options, - ) as ScalarHttpCanonicalization, - value: this.engine.mutate( - this.sourceType.indexer.value, - this.options.with(newIndexerOptions), - ), - }; - - return; - } + protected startIndexerValueEdge(): MutationHalfEdge { + return new MutationHalfEdge("indexerValue", this, (tail) => { + this.#languageMutationNode.connectIndexerValue(tail.languageMutationNode); + this.#wireMutationNode.connectIndexerValue(tail.wireMutationNode); + }); + } - super.mutate(); + protected startIndexerKeyEdge(): MutationHalfEdge { + return new MutationHalfEdge("indexerKey", this, (tail) => { + this.#languageMutationNode.connectIndexerKey(tail.languageMutationNode); + this.#wireMutationNode.connectIndexerKey(tail.wireMutationNode); + }); } /** diff --git a/packages/http-canonicalization/src/operation.test.ts b/packages/http-canonicalization/src/operation.test.ts index 6e8befa1b4f..0aa1e687fbe 100644 --- a/packages/http-canonicalization/src/operation.test.ts +++ b/packages/http-canonicalization/src/operation.test.ts @@ -1,4 +1,5 @@ -import { t, type TesterInstance } from "@typespec/compiler/testing"; +import type { Model } from "@typespec/compiler"; +import { expectTypeEquals, t, type TesterInstance } from "@typespec/compiler/testing"; import { $ } from "@typespec/compiler/typekit"; import { beforeEach, describe, expect, it } from "vitest"; import { Tester } from "../test/test-host.js"; @@ -28,7 +29,11 @@ describe("Operation parameters", async () => { const canonicalizer = new HttpCanonicalizer(tk); const createFooCanonical = canonicalizer.canonicalize(createFoo); - const bodyType = createFooCanonical.requestParameters.body!.type as ModelHttpCanonicalization; + const body = createFooCanonical.requestParameters.body!; + expect(body.bodyKind).toBe("single"); + if (body.bodyKind !== "single") throw new Error("Expected single body"); + expect(body.bodies.length).toBe(1); + const bodyType = body.bodies[0]!.type as ModelHttpCanonicalization; expect(bodyType).toBeDefined(); expect(bodyType).toBeInstanceOf(ModelHttpCanonicalization); const fooProp = bodyType.properties.get("foo")!; @@ -56,7 +61,11 @@ describe("Operation parameters", async () => { const tk = $(program); const canonicalizer = new HttpCanonicalizer(tk); const createFooCanonical = canonicalizer.canonicalize(createFoo); - const bodyType = createFooCanonical.requestParameters.body!.type as ModelHttpCanonicalization; + const body = createFooCanonical.requestParameters.body!; + expect(body.bodyKind).toBe("single"); + if (body.bodyKind !== "single") throw new Error("Expected single body"); + expect(body.bodies.length).toBe(1); + const bodyType = body.bodies[0]!.type as ModelHttpCanonicalization; expect(bodyType).toBeDefined(); expect(bodyType).toBeInstanceOf(ModelHttpCanonicalization); expect(bodyType.languageType.name).toBe("FooCreate"); @@ -80,10 +89,92 @@ describe("Operation parameters", async () => { const dateProp = createFooCanonical.requestParameters.properties[0]; expect(dateProp.kind).toBe("header"); const scalarType = dateProp.property.type as ScalarHttpCanonicalization; - expect(scalarType.wireType === tk.builtin.string).toBe(true); + expectTypeEquals(scalarType.wireType, tk.builtin.string); expect(scalarType.codec.id).toBe("rfc7231"); expect(createFooCanonical.requestParameters.properties.length).toBe(2); }); + + it("works with merge patch", async () => { + const { updateFoo, program } = await runner.compile(t.code` + model ${t.model("Foo")} { + @visibility(Lifecycle.Read) createdAt: utcDateTime; + name: string; + } + + @route("/foo") + @patch + op ${t.op("updateFoo")}(@body body: MergePatchUpdate): Foo; + `); + + const tk = $(program); + const canonicalizer = new HttpCanonicalizer(tk); + const updateFooCanonical = canonicalizer.canonicalize(updateFoo); + const body = updateFooCanonical.requestParameters.body!; + expect(body.bodyKind).toBe("single"); + if (body.bodyKind !== "single") throw new Error("Expected single body"); + const bodyProp = body.bodies[0]!.property!; + expect(bodyProp.languageType.name).toBe("body"); + expect((bodyProp.languageType.type as Model).name).toBe("FooMergePatchUpdate"); + expect(body.bodies.length).toBe(1); + expect(body.bodies[0]!.type).toBeInstanceOf(ModelHttpCanonicalization); + expect((body.bodies[0]!.type.languageType as Model).name).toBe("FooMergePatchUpdate"); + }); + + it("has the same canonicalization for bodies inside and outside parameters", async () => { + const { createFoo, program } = await runner.compile(t.code` + model ${t.model("Foo")} { + name: string; + } + + @route("/foo") + @post + op ${t.op("createFoo")}(@body body: Foo): Foo; + `); + + const tk = $(program); + const canonicalizer = new HttpCanonicalizer(tk); + const createFooCanonical = canonicalizer.canonicalize(createFoo); + const body = createFooCanonical.requestParameters.body!; + expect(body.bodyKind).toBe("single"); + if (body.bodyKind !== "single") throw new Error("Expected single body"); + const viaBody = body.bodies[0]!.type; + const viaProp = createFooCanonical.requestParameters.properties[0]!.property + .type as ModelHttpCanonicalization; + expect(viaBody === viaProp).toBe(true); + }); + + it("handles multiple content types", async () => { + const { createFoo, program } = await runner.compile(t.code` + model ${t.model("Foo")} { + name: string; + } + + @route("/foo") + @post + op ${t.op("createFoo")}(@header("Content-Type") contentType: "application/json" | "application/xml", @body body: Foo): Foo; + `); + + const tk = $(program); + const canonicalizer = new HttpCanonicalizer(tk); + const createFooCanonical = canonicalizer.canonicalize(createFoo); + const body = createFooCanonical.requestParameters.body!; + expect(body.bodyKind).toBe("single"); + if (body.bodyKind !== "single") throw new Error("Expected single body"); + + // Should have canonicalized bodies for both content types + expect(body.bodies.length).toBe(2); + expect(body.contentTypes).toEqual(["application/json", "application/xml"]); + + // Check first content type (application/json) + const jsonBody = body.bodies[0]!; + expect(jsonBody.contentType).toBe("application/json"); + expect(jsonBody.type).toBeInstanceOf(ModelHttpCanonicalization); + + // Check second content type (application/xml) + const xmlBody = body.bodies[1]!; + expect(xmlBody.contentType).toBe("application/xml"); + expect(xmlBody.type).toBeInstanceOf(ModelHttpCanonicalization); + }); }); describe("Operation responses", async () => { @@ -116,13 +207,15 @@ describe("Operation responses", async () => { const etagHeader = content.headers!.etag; expect(etagHeader).toBeDefined(); const etagType = etagHeader!.type as ScalarHttpCanonicalization; - expect(etagType.wireType === tk.builtin.string).toBe(true); + expectTypeEquals(etagType.wireType, tk.builtin.string); expect(content.body).toBeDefined(); const body = content.body!; expect(body.bodyKind).toBe("single"); + if (body.bodyKind !== "single") throw new Error("Expected single body"); - const bodyType = body.type as ModelHttpCanonicalization; + expect(body.bodies.length).toBe(1); + const bodyType = body.bodies[0]!.type as ModelHttpCanonicalization; expect(bodyType.visibleProperties.has("name")).toBe(true); expect(bodyType.visibleProperties.has("createdAt")).toBe(true); }); diff --git a/packages/http-canonicalization/src/operation.ts b/packages/http-canonicalization/src/operation.ts index a4b15abd7a3..4fb8f85f3f3 100644 --- a/packages/http-canonicalization/src/operation.ts +++ b/packages/http-canonicalization/src/operation.ts @@ -1,18 +1,28 @@ import type { MemberType, ModelProperty, Operation } from "@typespec/compiler"; import { - type HttpOperation, - type HttpVerb, resolveRequestVisibility, Visibility, + type HttpOperation, + type HttpVerb, } from "@typespec/http"; import "@typespec/http/experimental/typekit"; -import { OperationMutation } from "@typespec/mutator-framework"; +import { + MutationHalfEdge, + OperationMutation, + type MutationNodeForType, + type MutationTraits, +} from "@typespec/mutator-framework"; import type { HttpCanonicalization, HttpCanonicalizationMutations, } from "./http-canonicalization-classes.js"; -import type { HttpCanonicalizer } from "./http-canonicalization.js"; +import type { + CanonicalizationPredicate, + HttpCanonicalizationCommon, + HttpCanonicalizationInfo, + HttpCanonicalizer, +} from "./http-canonicalization.js"; import type { ModelPropertyHttpCanonicalization } from "./model-property.js"; import type { ModelHttpCanonicalization } from "./model.js"; import { HttpCanonicalizationOptions } from "./options.js"; @@ -170,12 +180,22 @@ export interface CanonicalHttpOperationBodyBase { readonly property?: ModelPropertyHttpCanonicalization; } -export interface CanonicalHttpBody { +export interface CanonicalHttpBodyForContentType { + /** The content type for this canonicalization. */ + readonly contentType: string; + /** The canonicalized type for this content type. */ readonly type: HttpCanonicalization; + /** The canonicalized property for this content type, if any. */ + readonly property?: ModelPropertyHttpCanonicalization; +} + +export interface CanonicalHttpBody { /** If the body was explicitly set with `@body`. */ readonly isExplicit: boolean; /** If the body contains metadata annotations to ignore. */ readonly containsMetadataAnnotations: boolean; + /** Canonicalized body for each content type. */ + readonly bodies: CanonicalHttpBodyForContentType[]; } export interface CanonicalHttpOperationBody @@ -273,18 +293,19 @@ export interface CanonicalHttpOperationFileBody extends CanonicalHttpOperationBo /** * Canonicalizes operations by deriving HTTP-specific request and response shapes. */ -export class OperationHttpCanonicalization extends OperationMutation< - HttpCanonicalizationOptions, - HttpCanonicalizationMutations, - HttpCanonicalizer -> { +export class OperationHttpCanonicalization + extends OperationMutation< + HttpCanonicalizationOptions, + HttpCanonicalizationMutations, + HttpCanonicalizer + > + implements HttpCanonicalizationCommon +{ /** * Cached HTTP metadata for this operation. */ #httpOperationInfo: HttpOperation; - /** - * Indicates if the operation corresponds to a named declaration. Always true. - */ + codec = null; isDeclaration: boolean = true; /** * Canonicalized request parameters grouped by location. @@ -331,32 +352,66 @@ export class OperationHttpCanonicalization extends OperationMutation< */ name: string; + #languageMutationNode: MutationNodeForType; + #wireMutationNode: MutationNodeForType; + /** - * Mutation subgraph for language types. + * The language mutation node for this operation. */ - get #languageSubgraph() { - return this.engine.getLanguageSubgraph(this.options); + get languageMutationNode() { + return this.#languageMutationNode; } /** - * Mutation subgraph for wire types. + * The wire mutation node for this operation. */ - get #wireSubgraph() { - return this.engine.getWireSubgraph(this.options); + get wireMutationNode() { + return this.#wireMutationNode; } /** * The language type for this operation. */ get languageType() { - return this.getMutatedType(this.#languageSubgraph); + return this.#languageMutationNode.mutatedType; } /** * The wire type for this operation. */ get wireType() { - return this.getMutatedType(this.#wireSubgraph); + return this.#wireMutationNode.mutatedType; + } + + /** + * Tests whether the subgraph rooted at this canonicalization uses only + * the identity codec (no transformation). + */ + subgraphUsesIdentityCodec(): boolean { + return this.engine.subgraphUsesIdentityCodec(this); + } + + /** + * Tests whether the subgraph rooted at this canonicalization satisfies + * the provided predicate. + */ + subgraphMatchesPredicate(predicate: CanonicalizationPredicate): boolean { + return this.engine.subgraphMatchesPredicate(this, predicate); + } + + static mutationInfo( + engine: HttpCanonicalizer, + sourceType: Operation, + referenceTypes: MemberType[], + options: HttpCanonicalizationOptions, + halfEdge?: MutationHalfEdge, + traits?: MutationTraits, + ): HttpCanonicalizationInfo { + return { + mutationKey: options.mutationKey, + codec: null as any, // Operations don't need a codec + isSynthetic: traits?.isSynthetic, + }; } constructor( @@ -364,8 +419,17 @@ export class OperationHttpCanonicalization extends OperationMutation< sourceType: Operation, referenceTypes: MemberType[] = [], options: HttpCanonicalizationOptions, + info: HttpCanonicalizationInfo, ) { - super(engine, sourceType, referenceTypes, options); + super(engine, sourceType, referenceTypes, options, info); + this.#languageMutationNode = this.engine.getMutationNode( + this.sourceType, + info.mutationKey + "-language", + ); + this.#wireMutationNode = this.engine.getMutationNode( + this.sourceType, + info.mutationKey + "-wire", + ); this.#httpOperationInfo = this.engine.$.httpOperation.get(this.sourceType); this.uriTemplate = this.#httpOperationInfo.uriTemplate; @@ -380,6 +444,20 @@ export class OperationHttpCanonicalization extends OperationMutation< this.method = this.#httpOperationInfo.verb; } + protected startParametersEdge(): MutationHalfEdge { + return new MutationHalfEdge("parameters", this, (tail) => { + this.#languageMutationNode.connectParameters(tail.languageMutationNode); + this.#wireMutationNode.connectParameters(tail.wireMutationNode); + }); + } + + protected startReturnTypeEdge(): MutationHalfEdge { + return new MutationHalfEdge("returnType", this, (tail) => { + this.#languageMutationNode.connectReturnType(tail.languageMutationNode); + this.#wireMutationNode.connectReturnType(tail.wireMutationNode); + }); + } + /** * Canonicalize this mutation for HTTP. */ @@ -413,7 +491,7 @@ export class OperationHttpCanonicalization extends OperationMutation< for (const param of paramInfo.properties) { this.requestParameters.properties.push( - this.#canonicalizeHttpProperty(param, this.parameterVisibility), + this.#canonicalizeHttpProperty(param, this.parameterVisibility, paramInfo.body), ); } @@ -466,9 +544,10 @@ export class OperationHttpCanonicalization extends OperationMutation< return { properties: content.properties.map((property) => - this.#canonicalizeHttpProperty(property, this.returnTypeVisibility), + this.#canonicalizeHttpProperty(property, this.returnTypeVisibility, content.body), ), headers: Object.keys(canonicalHeaders).length > 0 ? canonicalHeaders : undefined, + body: content.body ? this.#canonicalizeBody(content.body, this.returnTypeVisibility) : undefined, @@ -481,8 +560,23 @@ export class OperationHttpCanonicalization extends OperationMutation< #canonicalizeHttpProperty( property: HttpOperationPropertyInfo, visibility: Visibility, + bodyInfo?: HttpPayloadBodyInfo, ): CanonicalHttpProperty { - const canonicalProperty = this.#canonicalizeModelProperty(property.property, visibility); + // For body-related properties, we need to pass the content type from the body info + const contentType = + bodyInfo && + (property.kind === "body" || + property.kind === "bodyRoot" || + property.kind === "multipartBody" || + property.kind === "bodyProperty") + ? bodyInfo.contentTypes[0] + : undefined; + + const canonicalProperty = this.#canonicalizeModelProperty( + property.property, + visibility, + contentType, + ); switch (property.kind) { case "header": @@ -581,15 +675,18 @@ export class OperationHttpCanonicalization extends OperationMutation< contentTypeProperty: body.contentTypeProperty ? this.#canonicalizeModelProperty(body.contentTypeProperty, visibility) : undefined, - property: body.property - ? this.#canonicalizeModelProperty(body.property, visibility) - : undefined, - type: this.engine.canonicalize(body.type, { - visibility, - contentType: body.contentTypes[0], - }) as HttpCanonicalization, isExplicit: body.isExplicit, containsMetadataAnnotations: body.containsMetadataAnnotations, + bodies: body.contentTypes.map((contentType) => ({ + contentType, + type: this.engine.canonicalize(body.type, { + visibility, + contentType, + }) as HttpCanonicalization, + property: body.property + ? this.#canonicalizeModelProperty(body.property, visibility, contentType) + : undefined, + })), } satisfies CanonicalHttpOperationBody; case "multipart": return this.#canonicalizeMultipartBody(body, visibility); @@ -718,8 +815,12 @@ export class OperationHttpCanonicalization extends OperationMutation< #canonicalizeModelProperty( property: ModelProperty, visibility: Visibility, + contentType?: string, ): ModelPropertyHttpCanonicalization { - return this.engine.canonicalize(property, new HttpCanonicalizationOptions({ visibility })); + return this.engine.canonicalize( + property, + new HttpCanonicalizationOptions({ visibility, contentType }), + ); } /** diff --git a/packages/http-canonicalization/src/options.ts b/packages/http-canonicalization/src/options.ts index ef7e7d40042..6a66ff55cf6 100644 --- a/packages/http-canonicalization/src/options.ts +++ b/packages/http-canonicalization/src/options.ts @@ -1,5 +1,6 @@ import { Visibility } from "@typespec/http"; import { MutationOptions } from "@typespec/mutator-framework"; +import type { HttpCanonicalization } from "./http-canonicalization-classes.js"; export type HttpCanonicalizationLocation = | "header" @@ -14,20 +15,23 @@ export interface HttpCanonicalizationOptionsInit { visibility?: Visibility; location?: HttpCanonicalizationLocation; contentType?: string; + namePolicy?: (canonicalization: HttpCanonicalization) => string | undefined; } export class HttpCanonicalizationOptions extends MutationOptions { visibility: Visibility; location: HttpCanonicalizationLocation; contentType: string; + namePolicy?: (canonicalization: HttpCanonicalization) => string | undefined; constructor(options: HttpCanonicalizationOptionsInit = {}) { super(); this.visibility = options.visibility ?? Visibility.All; this.location = options.location ?? "body"; this.contentType = options.contentType ?? "none"; + this.namePolicy = options.namePolicy; } - cacheKey(): string { + get mutationKey(): string { return `visibility:${this.visibility}|location:${this.location}|contentType:${this.contentType}`; } @@ -36,10 +40,7 @@ export class HttpCanonicalizationOptions extends MutationOptions { visibility: newOptions.visibility ?? this.visibility, location: newOptions.location ?? this.location, contentType: newOptions.contentType ?? this.contentType, + namePolicy: newOptions.namePolicy ?? this.namePolicy, }); } - - isJsonMergePatch(): boolean { - return this.contentType === "application/merge-patch+json"; - } } diff --git a/packages/http-canonicalization/src/scalar.test.ts b/packages/http-canonicalization/src/scalar.test.ts index 58d6f3e1a28..ec832d8e52c 100644 --- a/packages/http-canonicalization/src/scalar.test.ts +++ b/packages/http-canonicalization/src/scalar.test.ts @@ -1,4 +1,4 @@ -import { t, type TesterInstance } from "@typespec/compiler/testing"; +import { expectTypeEquals, t, type TesterInstance } from "@typespec/compiler/testing"; import { $ } from "@typespec/compiler/typekit"; import { Visibility } from "@typespec/http"; import { beforeEach, expect, it } from "vitest"; @@ -24,9 +24,9 @@ it("canonicalizes a string", async () => { }); // No mutation happens in this case, so: - expect(canonicalMyString.sourceType === canonicalMyString.languageType).toBe(true); + expectTypeEquals(canonicalMyString.sourceType, canonicalMyString.languageType); - expect(canonicalMyString.sourceType === canonicalMyString.wireType).toBe(true); + expectTypeEquals(canonicalMyString.sourceType, canonicalMyString.wireType); expect(canonicalMyString.codec.id).toBe("identity"); }); @@ -39,17 +39,17 @@ it("canonicalizes an int32 scalar", async () => { const tk = $(program); const engine = new HttpCanonicalizer(tk); - const canonicalMyString = engine.canonicalize(myNumber, { + const canonicalMyNumber = engine.canonicalize(myNumber, { visibility: Visibility.Read, + contentType: "application/json", }); // We leave the language type the same - expect(canonicalMyString.sourceType === canonicalMyString.languageType).toBe(true); - + expectTypeEquals(canonicalMyNumber.sourceType, canonicalMyNumber.languageType); // but the wire type is a float64 - expect(canonicalMyString.sourceType === canonicalMyString.wireType).toBe(false); - expect(canonicalMyString.wireType === tk.builtin.float64).toBe(true); - expect(canonicalMyString.codec.id).toBe("coerce-to-float64"); + expect(canonicalMyNumber.sourceType === canonicalMyNumber.wireType).toBe(false); + expectTypeEquals(canonicalMyNumber.wireType, tk.builtin.float64); + expect(canonicalMyNumber.codec.id).toBe("coerce-to-float64"); }); it("canonicalizes a utcDateTime scalar", async () => { @@ -62,9 +62,10 @@ it("canonicalizes a utcDateTime scalar", async () => { const canonicalMyString = engine.canonicalize(myDateTime, { visibility: Visibility.Read, + contentType: "application/json", }); - expect(canonicalMyString.wireType === tk.builtin.string).toBe(true); + expectTypeEquals(canonicalMyString.wireType, tk.builtin.string); expect(canonicalMyString.codec.id).toBe("rfc3339"); }); @@ -79,17 +80,18 @@ it("canonicalizes a utcDateTime scalar with encode decorator", async () => { const canonicalMyString = engine.canonicalize(myDateTime, { visibility: Visibility.Read, + contentType: "application/json", }); // the codec is set appropriately expect(canonicalMyString.codec.id).toBe("rfc7231"); // We leave the language type the same - expect(canonicalMyString.sourceType === canonicalMyString.languageType).toBe(true); + expectTypeEquals(canonicalMyString.sourceType, canonicalMyString.languageType); // but the wire type is a string expect(canonicalMyString.sourceType === canonicalMyString.wireType).toBe(false); - expect(canonicalMyString.wireType === tk.builtin.string).toBe(true); + expectTypeEquals(canonicalMyString.wireType, tk.builtin.string); }); it("canonicalizes a utcDateTime scalar with encode decorator on a member", async () => { @@ -105,6 +107,7 @@ it("canonicalizes a utcDateTime scalar with encode decorator on a member", async const engine = new HttpCanonicalizer(tk); const canonicalFoo = engine.canonicalize(Foo, { visibility: Visibility.Read, + contentType: "application/json", }); // navigating canonicalization @@ -112,11 +115,39 @@ it("canonicalizes a utcDateTime scalar with encode decorator on a member", async .type as ScalarHttpCanonicalization; expect(canonicalDateTime).toBeInstanceOf(ScalarHttpCanonicalization); - expect(canonicalDateTime.wireType === tk.builtin.string).toBe(true); + expectTypeEquals(canonicalDateTime.wireType, tk.builtin.string); expect(canonicalDateTime.codec.id).toBe("rfc7231"); // navigating mutated type const wireFoo = canonicalFoo.wireType; const wireDateType = wireFoo.properties.get("createdAt")!.type; - expect(wireDateType === tk.builtin.string).toBe(true); + expectTypeEquals(wireDateType, tk.builtin.string); +}); + +it("canonicalizes a unix timestamp", async () => { + const { myDateTime1, myDateTime2, program } = await runner.compile(t.code` + @encode("unixTimestamp", int32) + scalar ${t.scalar("myDateTime1")} extends utcDateTime; + @encode(DateTimeKnownEncoding.unixTimestamp, int32) + scalar ${t.scalar("myDateTime2")} extends utcDateTime; + `); + + const tk = $(program); + const engine = new HttpCanonicalizer(tk); + + const canonicalDate1 = engine.canonicalize(myDateTime1, { + visibility: Visibility.Read, + contentType: "application/json", + }); + + // the codec is set appropriately + expect(canonicalDate1.codec.id).toBe("unix-timestamp-32"); + + const canonicalDate2 = engine.canonicalize(myDateTime2, { + visibility: Visibility.Read, + contentType: "application/json", + }); + + // the codec is set appropriately + expect(canonicalDate2.codec.id).toBe("unix-timestamp-32"); }); diff --git a/packages/http-canonicalization/src/scalar.ts b/packages/http-canonicalization/src/scalar.ts index 67bf3079ff4..3ae9ba5e13d 100644 --- a/packages/http-canonicalization/src/scalar.ts +++ b/packages/http-canonicalization/src/scalar.ts @@ -1,57 +1,89 @@ import type { MemberType, Scalar } from "@typespec/compiler"; -import { ScalarMutation } from "@typespec/mutator-framework"; -import { getJsonEncoderRegistry, type Codec } from "./codecs.js"; +import { + MutationHalfEdge, + ScalarMutation, + type MutationNodeForType, + type MutationTraits, +} from "@typespec/mutator-framework"; +import { type Codec, type EncodingInfo } from "./codecs.js"; import type { HttpCanonicalizationMutations } from "./http-canonicalization-classes.js"; -import type { HttpCanonicalizer } from "./http-canonicalization.js"; +import type { + CanonicalizationPredicate, + HttpCanonicalizationCommon, + HttpCanonicalizationInfo, + HttpCanonicalizer, +} from "./http-canonicalization.js"; import { HttpCanonicalizationOptions } from "./options.js"; /** * Canonicalizes scalar types by applying encoding-specific mutations. */ -export class ScalarHttpCanonicalization extends ScalarMutation< - HttpCanonicalizationOptions, - HttpCanonicalizationMutations, - HttpCanonicalizer -> { - /** - * Canonicalization options. - */ - options: HttpCanonicalizationOptions; - /** - * Codec responsible for transforming the scalar into language and wire types. - */ +export class ScalarHttpCanonicalization + extends ScalarMutation< + HttpCanonicalizationOptions, + HttpCanonicalizationMutations, + HttpCanonicalizer + > + implements HttpCanonicalizationCommon +{ codec: Codec; - /** - * Indicates whether the scalar is a named TypeSpec declaration. - */ + #encodingInfo: EncodingInfo; isDeclaration: boolean = false; - /** - * Mutation subgraph for language types. - */ - get #languageSubgraph() { - return this.engine.getLanguageSubgraph(this.options); + #languageMutationNode: MutationNodeForType; + get languageMutationNode() { + return this.#languageMutationNode; } - /** - * Mutation subgraph for wire types. - */ - get #wireSubgraph() { - return this.engine.getWireSubgraph(this.options); + #wireMutationNode: MutationNodeForType; + get wireMutationNode() { + return this.#wireMutationNode; + } + + get languageType() { + return this.#languageMutationNode.mutatedType; + } + + get wireType() { + return this.#wireMutationNode.mutatedType; } /** - * The possibly mutated language type for this scalar. + * Tests whether the subgraph rooted at this canonicalization uses only + * the identity codec (no transformation). */ - get languageType() { - return this.getMutatedType(this.#languageSubgraph); + subgraphUsesIdentityCodec(): boolean { + return this.engine.subgraphUsesIdentityCodec(this); } /** - * The possibly mutated wire type for this scalar. + * Tests whether the subgraph rooted at this canonicalization satisfies + * the provided predicate. */ - get wireType() { - return this.getMutatedType(this.#wireSubgraph); + subgraphMatchesPredicate(predicate: CanonicalizationPredicate): boolean { + return this.engine.subgraphMatchesPredicate(this, predicate); + } + + static mutationInfo( + engine: HttpCanonicalizer, + sourceType: Scalar, + referenceTypes: MemberType[], + options: HttpCanonicalizationOptions, + halfEdge?: MutationHalfEdge, + traits?: MutationTraits, + ): HttpCanonicalizationInfo { + let mutationKey = options.mutationKey; + const encodingInfo = engine.codecs.encode(sourceType, referenceTypes); + + if (encodingInfo.codec) { + mutationKey += `-codec-${encodingInfo.codec.id}`; + } + + return { + mutationKey, + encodingInfo, + isSynthetic: traits?.isSynthetic, + }; } constructor( @@ -59,12 +91,21 @@ export class ScalarHttpCanonicalization extends ScalarMutation< sourceType: Scalar, referenceTypes: MemberType[], options: HttpCanonicalizationOptions, + info: HttpCanonicalizationInfo, ) { - super(engine, sourceType, referenceTypes, options); + super(engine, sourceType, referenceTypes, options, info); this.options = options; + this.#languageMutationNode = this.engine.getMutationNode( + this.sourceType, + info.mutationKey + "-language", + ); + this.#wireMutationNode = this.engine.getMutationNode( + this.sourceType, + info.mutationKey + "-wire", + ); - const registry = getJsonEncoderRegistry(this.engine.$); - this.codec = registry.detect(this); + this.#encodingInfo = info.encodingInfo!; + this.codec = info.encodingInfo!.codec; this.isDeclaration = false; } @@ -72,15 +113,23 @@ export class ScalarHttpCanonicalization extends ScalarMutation< * Canonicalize this scalar for HTTP. */ mutate() { - const languageNode = this.getMutationNode(this.#languageSubgraph); - const wireNode = this.getMutationNode(this.#wireSubgraph); - - const { languageType, wireType } = this.codec.encode(); + const { languageType, wireType } = this.#encodingInfo; if (languageType !== this.sourceType) { - languageNode.replace(languageType as Scalar); + this.#languageMutationNode = this.#languageMutationNode.replace( + languageType as Scalar, + ) as MutationNodeForType; } if (wireType !== this.sourceType) { - wireNode.replace(wireType as Scalar); + this.#wireMutationNode = this.#wireMutationNode.replace( + wireType as Scalar, + ) as MutationNodeForType; } } + + protected startBaseScalarEdge(): MutationHalfEdge { + return new MutationHalfEdge("base", this, (tail) => { + this.#languageMutationNode.connectBaseScalar(tail.languageMutationNode); + this.#wireMutationNode.connectBaseScalar(tail.wireMutationNode); + }); + } } diff --git a/packages/http-canonicalization/src/union-variant.ts b/packages/http-canonicalization/src/union-variant.ts index cec46814cbe..c5f5870bc9b 100644 --- a/packages/http-canonicalization/src/union-variant.ts +++ b/packages/http-canonicalization/src/union-variant.ts @@ -1,56 +1,86 @@ import type { MemberType, UnionVariant } from "@typespec/compiler"; -import { UnionVariantMutation } from "@typespec/mutator-framework"; +import { + MutationHalfEdge, + UnionVariantMutation, + type MutationNodeForType, + type MutationTraits, +} from "@typespec/mutator-framework"; +import type { Codec } from "./codecs.js"; import type { HttpCanonicalizationMutations } from "./http-canonicalization-classes.js"; -import type { HttpCanonicalizer } from "./http-canonicalization.js"; +import type { + CanonicalizationPredicate, + HttpCanonicalizationCommon, + HttpCanonicalizationInfo, + HttpCanonicalizer, +} from "./http-canonicalization.js"; import { HttpCanonicalizationOptions } from "./options.js"; /** * Canonicalizes a union variant for HTTP. */ -export class UnionVariantHttpCanonicalization extends UnionVariantMutation< - HttpCanonicalizationOptions, - HttpCanonicalizationMutations, - HttpCanonicalizer -> { - /** - * Canonicalization options. - */ - options: HttpCanonicalizationOptions; - /** - * Indicates if the variant corresponds to a named declaration. Always false. - */ +export class UnionVariantHttpCanonicalization + extends UnionVariantMutation< + HttpCanonicalizationOptions, + HttpCanonicalizationMutations, + HttpCanonicalizer + > + implements HttpCanonicalizationCommon +{ isDeclaration: boolean = false; + codec: Codec | null = null; /** * Whether the variant is visible under the current visibility options. */ isVisible: boolean = true; - /** - * Mutation subgraph for language types. - */ - get #languageSubgraph() { - return this.engine.getLanguageSubgraph(this.options); + #languageMutationNode: MutationNodeForType; + #wireMutationNode: MutationNodeForType; + + get languageMutationNode() { + return this.#languageMutationNode; } - /** - * Mutation subgraph for wire types. - */ - get #wireSubgraph() { - return this.engine.getWireSubgraph(this.options); + get wireMutationNode() { + return this.#wireMutationNode; + } + + get languageType() { + return this.#languageMutationNode.mutatedType; + } + + get wireType() { + return this.#wireMutationNode.mutatedType; } /** - * The possibly mutated language type for this variant. + * Tests whether the subgraph rooted at this canonicalization uses only + * the identity codec (no transformation). */ - get languageType() { - return this.getMutatedType(this.#languageSubgraph); + subgraphUsesIdentityCodec(): boolean { + return this.engine.subgraphUsesIdentityCodec(this); } /** - * The possibly mutated wire type for this variant. + * Tests whether the subgraph rooted at this canonicalization satisfies + * the provided predicate. */ - get wireType() { - return this.getMutatedType(this.#wireSubgraph); + subgraphMatchesPredicate(predicate: CanonicalizationPredicate): boolean { + return this.engine.subgraphMatchesPredicate(this, predicate); + } + + static mutationInfo( + engine: HttpCanonicalizer, + sourceType: UnionVariant, + referenceTypes: MemberType[], + options: HttpCanonicalizationOptions, + halfEdge?: MutationHalfEdge, + traits?: MutationTraits, + ): HttpCanonicalizationInfo { + return { + mutationKey: options.mutationKey, + codec: null as any, // Union variants don't need a codec + isSynthetic: traits?.isSynthetic, + }; } constructor( @@ -58,25 +88,38 @@ export class UnionVariantHttpCanonicalization extends UnionVariantMutation< sourceType: UnionVariant, referenceTypes: MemberType[], options: HttpCanonicalizationOptions, + info: HttpCanonicalizationInfo, ) { - super(engine, sourceType, referenceTypes, options); + super(engine, sourceType, referenceTypes, options, info); this.options = options; + this.#languageMutationNode = this.engine.getMutationNode( + this.sourceType, + info.mutationKey + "-language", + ); + this.#wireMutationNode = this.engine.getMutationNode( + this.sourceType, + info.mutationKey + "-wire", + ); this.isDeclaration = !!this.sourceType.name; } + protected startTypeEdge(): MutationHalfEdge { + return new MutationHalfEdge("type", this, (tail) => { + this.#languageMutationNode.connectType(tail.languageMutationNode); + this.#wireMutationNode.connectType(tail.wireMutationNode); + }); + } + /** * Canonicalize this union variant for HTTP. */ mutate() { - const languageNode = this.getMutationNode(this.#languageSubgraph); - const wireNode = this.getMutationNode(this.#wireSubgraph); - if (this.isVisible) { super.mutate(); return; } - languageNode.delete(); - wireNode.delete(); + this.#languageMutationNode.delete(); + this.#wireMutationNode.delete(); } } diff --git a/packages/http-canonicalization/src/union.test.ts b/packages/http-canonicalization/src/union.test.ts index c0597d1a480..9d075d722dd 100644 --- a/packages/http-canonicalization/src/union.test.ts +++ b/packages/http-canonicalization/src/union.test.ts @@ -1,3 +1,4 @@ +import type { Model } from "@typespec/compiler"; import { t, type TesterInstance } from "@typespec/compiler/testing"; import { $ } from "@typespec/compiler/typekit"; import { Visibility } from "@typespec/http"; @@ -12,6 +13,39 @@ beforeEach(async () => { runner = await Tester.createInstance(); }); +it("works with discriminated unions without envelope", async () => { + const { Choice, program } = await runner.compile(t.code` + model ${t.model("First")} { kind: "first"; } + model ${t.model("Second")} { kind: "second"; } + + @discriminated(#{ envelope: "none", discriminatorPropertyName: "kind" }) + union ${t.union("Choice")} { + first: First; + second: Second; + } + `); + + const canonicalizer = new HttpCanonicalizer($(program)); + const canonical = canonicalizer.canonicalize(Choice, { + visibility: Visibility.All, + }) as UnionHttpCanonicalization; + + expect(canonical.languageVariantTests.length).toBe(0); + expect(canonical.variantDescriptors.length).toBe(2); + + const [firstVariant, secondVariant] = canonical.variantDescriptors; + + expect(firstVariant.variant.sourceType.type).toBeDefined(); + expect((firstVariant.variant.sourceType.type as Model).name).toBe("First"); + expect(firstVariant.envelopeType).toBe(null); + expect(firstVariant.discriminatorValue).toBe("first"); + + expect(secondVariant.variant.sourceType.type).toBeDefined(); + expect((secondVariant.variant.sourceType.type as Model).name).toBe("Second"); + expect(secondVariant.envelopeType).toBe(null); + expect(secondVariant.discriminatorValue).toBe("second"); +}); + describe("UnionCanonicalization variant detection", () => { it("detects literal property discriminants for object unions", async () => { const { Choice, First, Second, program } = await runner.compile(t.code` @@ -38,7 +72,7 @@ describe("UnionCanonicalization variant detection", () => { expect(canonical.wireVariantTests).toEqual(canonical.languageVariantTests); }); - it("prioritizes primitives before object variants and prepends type guards", async () => { + it("orders and takes into account previous tests", async () => { const { Choice, First, Second, program } = await runner.compile(t.code` model ${t.model("First")} { kind: "first"; } model ${t.model("Second")} { kind: "second"; } @@ -51,9 +85,7 @@ describe("UnionCanonicalization variant detection", () => { }) as UnionHttpCanonicalization; expect(canonical.languageVariantTests.length).toBe(3); - - const [numberVariant, firstVariant, secondVariant] = canonical.languageVariantTests; - + const [firstVariant, secondVariant, numberVariant] = canonical.languageVariantTests; expect(numberVariant.variant.sourceType.type.kind).toBe("Scalar"); expect(numberVariant.tests).toEqual([{ kind: "type", path: [], type: "number" }]); @@ -64,10 +96,7 @@ describe("UnionCanonicalization variant detection", () => { ]); expect(secondVariant.variant.sourceType.type).toBe(Second); - expect(secondVariant.tests).toEqual([ - { kind: "type", path: [], type: "object" }, - { kind: "literal", path: ["kind"], value: "second" }, - ]); + expect(secondVariant.tests).toEqual([{ kind: "type", path: [], type: "object" }]); expect(canonical.wireVariantTests.map((entry) => entry.variant)).toEqual( canonical.languageVariantTests.map((entry) => entry.variant), @@ -111,6 +140,28 @@ describe("UnionCanonicalization variant detection", () => { canonicalizer.canonicalize(Choice, { visibility: Visibility.All, }); - }).rejects.toThrow(/Unable to distinguish union variant/); + }).rejects.toThrow(/Unable to distinguish language type/); + }); + + it("supports extensible union pattern", async () => { + const { Choice, program } = await runner.compile(t.code` + union ${t.union("Choice")} { + string; + "first"; + "second"; + } + `); + + const canonicalizer = new HttpCanonicalizer($(program)); + const canonical = canonicalizer.canonicalize(Choice, { + visibility: Visibility.All, + }); + + expect(canonical.languageVariantTests).toHaveLength(3); + expect(canonical.languageVariantTests.map((entry) => entry.tests)).toEqual([ + [{ kind: "literal", path: [], value: "first" }], + [{ kind: "literal", path: [], value: "second" }], + [{ kind: "type", path: [], type: "string" }], + ]); }); }); diff --git a/packages/http-canonicalization/src/union.ts b/packages/http-canonicalization/src/union.ts index 0ec2857cf0b..28925e625cb 100644 --- a/packages/http-canonicalization/src/union.ts +++ b/packages/http-canonicalization/src/union.ts @@ -11,12 +11,22 @@ import type { UnionVariant, } from "@typespec/compiler"; import { getVisibilitySuffix, Visibility } from "@typespec/http"; -import { UnionMutation } from "@typespec/mutator-framework"; +import { + MutationHalfEdge, + UnionMutation, + type MutationNodeForType, + type MutationTraits, +} from "@typespec/mutator-framework"; import type { HttpCanonicalization, HttpCanonicalizationMutations, } from "./http-canonicalization-classes.js"; -import type { HttpCanonicalizer } from "./http-canonicalization.js"; +import type { + CanonicalizationPredicate, + HttpCanonicalizationCommon, + HttpCanonicalizationInfo, + HttpCanonicalizer, +} from "./http-canonicalization.js"; import { ModelHttpCanonicalization } from "./model.js"; import { HttpCanonicalizationOptions } from "./options.js"; import type { UnionVariantHttpCanonicalization } from "./union-variant.jsx"; @@ -71,15 +81,15 @@ interface VariantTestDefinition { /** * Canonicalizes union types, tracking discriminators and runtime variant tests. */ -export class UnionHttpCanonicalization extends UnionMutation< - HttpCanonicalizationOptions, - HttpCanonicalizationMutations, - HttpCanonicalizer -> { - /** - * Canonicalization options guiding union transformation. - */ - options: HttpCanonicalizationOptions; +export class UnionHttpCanonicalization + extends UnionMutation< + HttpCanonicalizationOptions, + HttpCanonicalizationMutations, + HttpCanonicalizer + > + implements HttpCanonicalizationCommon +{ + codec = null; /** * Indicates if this union corresponds to a named declaration. */ @@ -128,32 +138,66 @@ export class UnionHttpCanonicalization extends UnionMutation< */ envelopePropertyName: string | null = null; + #languageMutationNode: MutationNodeForType; + #wireMutationNode: MutationNodeForType; + /** - * Mutation subgraph for language types. + * The language mutation node for this union. */ - get #languageSubgraph() { - return this.engine.getLanguageSubgraph(this.options); + get languageMutationNode() { + return this.#languageMutationNode; } /** - * Mutation subgraph for wire types. + * The wire mutation node for this union. */ - get #wireSubgraph() { - return this.engine.getWireSubgraph(this.options); + get wireMutationNode() { + return this.#wireMutationNode; } /** * The potentially mutated language type for this union. */ get languageType() { - return this.getMutatedType(this.#languageSubgraph); + return this.#languageMutationNode.mutatedType; } /** * The potentially mutated wire type for this union. */ get wireType() { - return this.getMutatedType(this.#wireSubgraph); + return this.#wireMutationNode.mutatedType; + } + + /** + * Tests whether the subgraph rooted at this canonicalization uses only + * the identity codec (no transformation). + */ + subgraphUsesIdentityCodec(): boolean { + return this.engine.subgraphUsesIdentityCodec(this); + } + + /** + * Tests whether the subgraph rooted at this canonicalization satisfies + * the provided predicate. + */ + subgraphMatchesPredicate(predicate: CanonicalizationPredicate): boolean { + return this.engine.subgraphMatchesPredicate(this, predicate); + } + + static mutationInfo( + engine: HttpCanonicalizer, + sourceType: Union, + referenceTypes: MemberType[], + options: HttpCanonicalizationOptions, + halfEdge?: MutationHalfEdge, + traits?: MutationTraits, + ): HttpCanonicalizationInfo { + return { + mutationKey: options.mutationKey, + codec: null as any, // Unions don't need a codec + isSynthetic: traits?.isSynthetic, + }; } constructor( @@ -161,17 +205,39 @@ export class UnionHttpCanonicalization extends UnionMutation< sourceType: Union, referenceTypes: MemberType[], options: HttpCanonicalizationOptions, + info: HttpCanonicalizationInfo, ) { - super(engine, sourceType, referenceTypes, options); + super(engine, sourceType, referenceTypes, options, info); + this.#languageMutationNode = this.engine.getMutationNode(this.sourceType, { + mutationKey: info.mutationKey + "-language", + isSynthetic: info.isSynthetic, + }); + this.#wireMutationNode = this.engine.getMutationNode(this.sourceType, { + mutationKey: info.mutationKey + "-wire", + isSynthetic: info.isSynthetic, + }); + this.options = options; this.isDeclaration = !!this.sourceType.name; this.#discriminatedUnionInfo = this.engine.$.union.getDiscriminatedUnion(sourceType) ?? null; this.isDiscriminated = !!this.#discriminatedUnionInfo; - this.envelopePropertyName = this.#discriminatedUnionInfo?.options.envelopePropertyName ?? null; + this.envelopeKind = this.#discriminatedUnionInfo?.options.envelope ?? "none"; + this.envelopePropertyName = null; + if (this.#discriminatedUnionInfo?.options.envelope !== "none") { + this.envelopePropertyName = + this.#discriminatedUnionInfo?.options.envelopePropertyName ?? null; + } this.discriminatorPropertyName = this.#discriminatedUnionInfo?.options.discriminatorPropertyName ?? null; } + protected startVariantEdge(): MutationHalfEdge { + return new MutationHalfEdge("variant", this, (tail) => { + this.#languageMutationNode.connectVariant(tail.languageMutationNode); + this.#wireMutationNode.connectVariant(tail.wireMutationNode); + }); + } + /** * Returns variants that remain visible under the current visibility rules. */ @@ -187,12 +253,8 @@ export class UnionHttpCanonicalization extends UnionMutation< * Canonicalize this union for HTTP. */ mutate() { - const languageNode = this.getMutationNode(this.#languageSubgraph); - languageNode.whenMutated(this.#renameWhenMutated.bind(this)); - - const wireNode = this.getMutationNode(this.#wireSubgraph); - wireNode.whenMutated(this.#renameWhenMutated.bind(this)); - + this.#languageMutationNode.whenMutated(this.#renameWhenMutated.bind(this)); + this.#wireMutationNode.whenMutated(this.#renameWhenMutated.bind(this)); super.mutate(); if (this.isDiscriminated) { @@ -204,24 +266,28 @@ export class UnionHttpCanonicalization extends UnionMutation< throw new Error("symbolic variant names are not supported"); } + const canonicalizedVariant = variant as UnionVariantHttpCanonicalization; const descriptor: VariantDescriptor = { - variant, - envelopeType: this.engine.canonicalize( - this.engine.$.model.create({ - name: "", - properties: { - [discriminatorProp]: this.engine.$.modelProperty.create({ - name: discriminatorProp, - type: this.engine.$.literal.create(variantName), - }), - [envelopeProp]: this.engine.$.modelProperty.create({ - name: envelopeProp, - type: variant.languageType.type, - }), - }, - }), - this.options, - ) as unknown as ModelHttpCanonicalization, + variant: canonicalizedVariant, + envelopeType: + this.envelopeKind === "none" + ? null + : (this.engine.canonicalize( + this.engine.$.model.create({ + name: "", + properties: { + [discriminatorProp]: this.engine.$.modelProperty.create({ + name: discriminatorProp, + type: this.engine.$.literal.create(variantName), + }), + [envelopeProp]: this.engine.$.modelProperty.create({ + name: envelopeProp, + type: canonicalizedVariant.languageType.type, + }), + }, + }), + this.options, + ) as unknown as ModelHttpCanonicalization), discriminatorValue: variantName, }; @@ -240,6 +306,10 @@ export class UnionHttpCanonicalization extends UnionMutation< return; } + if (!mutated.name) { + return; + } + const suffix = getVisibilitySuffix(this.options.visibility, Visibility.Read); mutated.name = `${mutated.name}${suffix}`; @@ -280,13 +350,15 @@ export class UnionHttpCanonicalization extends UnionMutation< return a.index - b.index; }); + const alreadyTested: VariantAnalysis[] = []; return orderedAnalyses.map((analysis) => { - const selected = this.#selectTestsForVariant(analysis, analyses); + const selected = this.#selectTestsForVariant(analysis, analyses, alreadyTested, target); const tests = selected .slice() .sort((a, b) => this.#testPriority(a.test) - this.#testPriority(b.test)) .map((definition) => definition.test); + alreadyTested.push(analysis); return { variant: analysis.variant, tests }; }); } @@ -351,20 +423,32 @@ export class UnionHttpCanonicalization extends UnionMutation< /** * Chooses the minimal set of tests that uniquely identify a variant. + * Takes into account which variants have already been ruled out by earlier tests in the sequence. */ #selectTestsForVariant( analysis: VariantAnalysis, analyses: VariantAnalysis[], + alreadyTestedAnalyses: VariantAnalysis[], + target: "language" | "wire", ): VariantTestDefinition[] { - const others = analyses.filter((candidate) => candidate !== analysis); + // Filter out variants that have already been tested earlier in the sequence + const others = analyses.filter( + (candidate) => candidate !== analysis && !alreadyTestedAnalyses.includes(candidate), + ); if (analysis.availableTests.length === 0) { if (others.length === 0) { return []; } + const indistinguishableVariants = others + .map((other) => this.#getVariantDebugName(other.variant)) + .join(", "); + throw new Error( - `Unable to determine distinguishing runtime checks for union variant "${this.#getVariantDebugName(analysis.variant)}".`, + `Unable to determine distinguishing runtime checks for ${target} type of union variant "${this.#getVariantDebugName(analysis.variant)}". ` + + `Indistinguishable from: [${indistinguishableVariants}]. ` + + `Variant type category: ${analysis.typeCategory ?? "unknown"}.`, ); } @@ -376,14 +460,36 @@ export class UnionHttpCanonicalization extends UnionMutation< ); if (remaining.length === 0) { + // If there are no remaining variants to distinguish from, but we have tests available, + // prefer literal tests over type tests for better specificity + if (required.length === 0 && optional.length > 0) { + // Prefer a literal test if available, otherwise fall back to type test + const literalTest = optional.find((test) => test.test.kind === "literal"); + if (literalTest) { + return [literalTest]; + } + const typeTest = optional.find((test) => test.test.kind === "type"); + return typeTest ? [typeTest] : [optional[0]]; + } return required; } const optionalSubset = this.#findCoveringSubset(optional, remaining); if (!optionalSubset) { + const indistinguishableVariants = remaining + .map((other) => this.#getVariantDebugName(other.variant)) + .join(", "); + + const availableTestsDescription = analysis.availableTests + .map((test) => `${test.test.kind}(${test.test.path.join(".")})`) + .join(", "); + throw new Error( - `Unable to distinguish union variant "${this.#getVariantDebugName(analysis.variant)}" with available runtime checks.`, + `Unable to distinguish ${target} type of union variant "${this.#getVariantDebugName(analysis.variant)}" with available runtime checks. ` + + `Indistinguishable from: [${indistinguishableVariants}]. ` + + `Variant type category: ${analysis.typeCategory ?? "unknown"}. ` + + `Available tests: [${availableTestsDescription}].`, ); } @@ -626,22 +732,38 @@ export class UnionHttpCanonicalization extends UnionMutation< /** * Provides a deterministic priority used to order variants. + * Variants with const tests come first (more specific), followed by those with only type tests (more generic). */ #variantPriority(analysis: VariantAnalysis) { + // Prioritize variants with const tests (literals) - they're more specific + const hasConstTests = analysis.constTests.length > 0; + const constTestPriority = hasConstTests ? 0 : 100; + + // Then sort by type category + let typeCategoryPriority: number; switch (analysis.typeCategory) { case "number": - return 0; + typeCategoryPriority = 0; + break; case "boolean": - return 1; + typeCategoryPriority = 1; + break; case "string": - return 2; + typeCategoryPriority = 2; + break; case "array": - return 3; + typeCategoryPriority = 3; + break; case "object": - return 4; + typeCategoryPriority = 4; + break; default: - return 5; + typeCategoryPriority = 5; + break; } + + // Combine priorities: const tests first, then type category + return constTestPriority + typeCategoryPriority; } /** diff --git a/packages/mutator-framework/readme.md b/packages/mutator-framework/readme.md index d550760f41c..6625f1169e0 100644 --- a/packages/mutator-framework/readme.md +++ b/packages/mutator-framework/readme.md @@ -1,6 +1,6 @@ # Mutator Framework -** WARNING: THIS PACKAGE IS EXPERIMENTAL AND WILL CHANGE ** +**WARNING: THIS PACKAGE IS EXPERIMENTAL AND WILL CHANGE** This package provides utilities for building mutations of the TypeSpec type graph. Mutations are modifications to the original type graph that live in a @@ -17,323 +17,290 @@ At a high level you: - Instantiate a `MutationEngine` subtype (e.g. `SimpleMutationEngine`) with the `Typekit` from the TypeSpec program you want to mutate. -The key APIs are: +## Key Concepts -- `MutationEngine` – orchestrates creation, caching, and traversal of mutation nodes. -- `SimpleMutationEngine` – a convenience engine that exposes a single default mutation subgraph. -- `MutationOptions` – lets you parameterize a mutation run and cache its results. -- `ModelMutation`, `ModelPropertyMutation`, `UnionMutation`, `UnionVariantMutation`, - `OperationMutation`, etc. – base classes for crafting custom mutations per TypeSpec kind. -- `MutationSubgraph` – creates an isolated graph of mutated types that can be inspected or - retrieved later. -- `ModelMutationNode`, `ModelPropertyMutationNode`, `UnionMutationNode`, etc. - - nodes which represent the possible mutation of a particular type graph type. +### Mutations -## Getting Started +Mutations are abstract classes that control how each TypeSpec type kind is +traversed and transformed. They have a protocol based on a static `mutationInfo` +method that returns a unique `mutationKey` for that mutation. If a mutation with +the same key exists, it is reused; otherwise, a new mutation is constructed. -```ts -import type { Model, Program } from "@typespec/compiler"; -import { $, type Typekit } from "@typespec/compiler/typekit"; -import { SimpleMutationEngine } from "@typespec/mutator-framework"; +The `mutationInfo` method can also return a `Mutation` directly, useful for +constructing a mutation view "as if" the type graph looked different. -// Create a typekit for the program -const tk: Typekit = $(program); +### Mutation Nodes -// Instantiate an engine for running the mutations. -// Might be the built-in SimpleMutationEngine, or a -// custom `MutationEngine` subclass. -const engine = new SimpleMutationEngine(tk, { - Model: RenameModelMutation, // defined later in this guide -}); -const renamedMutation = engine.mutate(someType); -const mutatedType = renamedMutation.mutatedType; -``` +Mutation nodes represent individual type transformations. They are unique per +`(type, mutationKey)` pair. Connections between nodes are built lazily using +half-edges - mutations call `startXEdge()` methods to create a `MutationHalfEdge` +that gets connected when the target mutation is resolved. -## Defining Custom Mutation Options +### Key APIs + +- `MutationEngine` – orchestrates creation, caching, and traversal of mutations. +- `SimpleMutationEngine` – a convenience engine with Simple\* mutation classes + that expose a single mutated type per source type. +- `MutationOptions` – lets you parameterize a mutation run and provide a `mutationKey`. +- `MutationHalfEdge` – represents the head-end of a connection; the tail is set when + the target mutation is resolved. +- `ModelMutation`, `ModelPropertyMutation`, `UnionMutation`, etc. – abstract base + classes for crafting custom mutations per TypeSpec kind. +- `SimpleModelMutation`, `SimpleModelPropertyMutation`, etc. – concrete implementations + that expose `mutationNode` and `mutatedType` properties. -Options derive from `MutationOptions`. They let you tune mutations (for example, -to switch on features or change naming rules) and provide a cache key used to -memoize results. Extend the class and override `cacheKey()` to represent your -configuration. +## Getting Started ```ts -// rename-mutations.ts -import { MutationOptions } from "@typespec/mutator-framework"; +import type { Model, Program } from "@typespec/compiler"; +import { $ } from "@typespec/compiler/typekit"; +import { + SimpleModelMutation, + SimpleMutationEngine, + SimpleMutationOptions, +} from "@typespec/mutator-framework"; -export class RenameMutationOptions extends MutationOptions { - constructor( - readonly prefix: string, - readonly suffix: string, - ) { +// Define custom options with a mutationKey +class RenameMutationOptions extends SimpleMutationOptions { + constructor(readonly suffix: string) { super(); } - override cacheKey() { - return `${this.prefix}-${this.suffix}`; + get mutationKey() { + return this.suffix; } } -``` -## Creating a Custom Mutation Engine +// Define a custom mutation that renames models +class RenameModelMutation extends SimpleModelMutation { + mutate() { + if ("name" in this.sourceType && typeof this.sourceType.name === "string") { + this.mutationNode.mutate( + (type) => (type.name = `${this.sourceType.name}${this.options.suffix}`), + ); + } + super.mutate(); + } +} -`MutationEngine` is responsible for coordinating mutation nodes and subgraphs. Supply constructors -for each type kind you want to customize. Anything you omit defaults to the base implementations -(`ModelMutation`, `ModelPropertyMutation`, etc.). +// Create the engine and run mutations +const tk = $(program); +const engine = new SimpleMutationEngine(tk, { + Model: RenameModelMutation, +}); -You can also register additional mutation subgraphs. Each subgraph represents an isolated view of -the mutated graph. This is useful when you want to compare alternative transformations side by side -(for example, with different naming conventions). +const options = new RenameMutationOptions("Suf"); +const fooMutation = engine.mutate(fooModel, options); +console.log(fooMutation.mutatedType.name); // "FooSuf" +``` + +## Defining Custom Mutation Options + +Options derive from `MutationOptions` (or `SimpleMutationOptions` for simple +mutations). Override the `mutationKey` getter to provide a unique cache key for +your configuration. Mutations are cached per `(type, mutationKey)` pair. ```ts -// rename-mutations.ts -import { MutationEngine, type MutationSubgraph } from "@typespec/mutator-framework"; -import type { Typekit } from "@typespec/compiler/typekit"; - -export class RenameMutationEngine extends MutationEngine<{ Model: RenameModelMutation }> { - constructor(typekit: Typekit) { - super(typekit, { Model: RenameModelMutation }); - this.registerSubgraph("prefix"); - this.registerSubgraph("suffix"); +import { SimpleMutationOptions } from "@typespec/mutator-framework"; + +class RenameMutationOptions extends SimpleMutationOptions { + constructor(readonly suffix: string) { + super(); } - getPrefix(options: RenameMutationOptions): MutationSubgraph { - return this.getMutationSubgraph(options, "prefix"); + get mutationKey() { + return this.suffix; } - getSuffix(options: RenameMutationOptions): MutationSubgraph { - return this.getMutationSubgraph(options, "suffix"); + with(options: Partial<{ suffix: string }>) { + return new RenameMutationOptions(options.suffix ?? this.suffix); } } ``` -The base `MutationEngine` does not define a default subgraph. If you just need a single mutated -view, use the `SimpleMutationEngine`. It auto-registers a `"subgraph"` and wires -`getDefaultMutationSubgraph` for you: - -```ts -import { SimpleMutationEngine } from "@typespec/mutator-framework"; - -const engine = new SimpleMutationEngine(tk, { - Model: RenameModelMutation, -}); -``` - ## Writing Mutation Classes -Mutation classes derive from the base classes included in the framework. Each class receives the -engine, the source TypeSpec type, the list of reference members that referenced that type (if any), -and the options. Override `mutate()` to perform your transformations. - -Inside `mutate()` you can: +Mutation classes are abstract classes that derive from the base classes included +in the framework. Override `mutate()` to perform your transformations. -- Traverse connected types via `this.engine.mutate(...)` or `this.engine.mutateReference(...)`. -- Retrieve or create mutation nodes with `this.getMutationNode()`. -- Mutate values using `this.mutateType()` or `engine.mutateType(...)`. -- Switch subgraphs by calling `this.engine.getMutationSubgraph(...)`. +### The `mutationInfo` Protocol -### Example: Renaming Models in Multiple Subgraphs +Each mutation class has a static `mutationInfo` method that is called to +determine the unique key for a mutation. The default implementation uses +`options.mutationKey`. Override this to implement context-sensitive mutation +keys based on reference types or other factors: ```ts -// rename-mutations.ts -import { ModelMutation } from "@typespec/mutator-framework"; - -export class RenameModelMutation extends ModelMutation< - RenameMutationOptions, - { Model: RenameModelMutation }, - RenameMutationEngine -> { - get withPrefix() { - return this.getMutatedType(this.engine.getPrefix(this.options)); - } - - get withSuffix() { - return this.getMutatedType(this.engine.getSuffix(this.options)); +class RenameModelBasedOnReferenceMutation extends SimpleModelMutation { + static mutationInfo( + engine: SimpleMutationEngine<{ Model: RenameModelBasedOnReferenceMutation }>, + sourceType: Model, + referenceTypes: MemberType[], + options: SimpleMutationOptions, + halfEdge?: MutationHalfEdge, + traits?: MutationTraits, + ): MutationInfo { + // Different key based on whether this type was reached via a reference + if (referenceTypes.length === 0) { + return { + mutationKey: options.mutationKey + "-no-ref", + hasReference: false, + isSynthetic: traits?.isSynthetic, + }; + } + return { + mutationKey: options.mutationKey + "-has-ref", + hasReference: true, + isSynthetic: traits?.isSynthetic, + }; } mutate() { - if ("name" in this.sourceType && typeof this.sourceType.name === "string") { - this.mutateType(this.engine.getPrefix(this.options), (model) => { - model.name = `${this.options.prefix}${model.name}`; - }); - - this.mutateType(this.engine.getSuffix(this.options), (model) => { - model.name = `${model.name}${this.options.suffix}`; - }); + if (this.mutationInfo.hasReference) { + this.mutationNode.mutate((type) => (type.name = `${this.sourceType.name}Reference`)); } - - // Always call super.mutate() if you still want the base implementation - // to traverse properties, base models, indexers, etc. with the same options. super.mutate(); } } ``` -### Running the Mutation - -```ts -import type { Model, Program } from "@typespec/compiler"; -import { $ } from "@typespec/compiler/typekit"; -import { RenameMutationEngine, RenameMutationOptions } from "./rename-mutations.js"; - -export function applyRename(program: Program, fooModel: Model) { - const engine = new RenameMutationEngine($(program)); - const options = new RenameMutationOptions("Pre", "Suf"); +### Lazy Connections with Half-Edges - const fooMutation = engine.mutate(fooModel, options); - const prefixFoo = fooMutation.withPrefix; - const suffixFoo = fooMutation.withSuffix; +Connections between mutations are built lazily. Mutations provide `startXEdge()` +methods that return a `MutationHalfEdge`. Pass this half-edge to `engine.mutate()` +or related methods. When the target mutation is resolved, its mutation node is +connected to the originating mutation's node: - const propMutation = fooMutation.properties.get("prop")!; - const barMutation = propMutation.type as RenameModelMutation; +```ts +class SimpleModelMutation extends ModelMutation { + // Creates a half-edge for connecting to a property mutation + startPropertyEdge() { + return new MutationHalfEdge("property", this, (tail) => + this.mutationNode.connectProperty(tail.mutationNode), + ); + } - return { - prefixFoo, - suffixFoo, - barWithSuffix: barMutation.withSuffix, - }; + mutate() { + for (const prop of this.sourceType.properties.values()) { + // Pass the half-edge so the connection is made when resolved + this.engine.mutate(prop, this.options, this.startPropertyEdge()); + } + } } ``` -### Example: Mutating Referenced Types +### Replacing Referenced Types -`ModelPropertyMutation` exposes `mutateReference` and `replaceReferencedType` -helpers that make it easy to mutate types referenced by properties. When -mutating references, a clone of the referenced type is made, so changes to not -affect the referenced type. This enables references to reference a unique type -with mutations that are particular to that type when referenced in that context. -For example, if the model property contains a decorator that affects the -mutation of a referenced scalar. +Use `engine.replaceAndMutateReference()` to substitute a type with a different +one while preserving the reference chain. This is useful for wrapping types in +unions or other containers: ```ts -import type { Model, Program } from "@typespec/compiler"; -import { $ } from "@typespec/compiler/typekit"; -import { - ModelMutation, - ModelPropertyMutation, - MutationOptions, - SimpleMutationEngine, -} from "@typespec/mutator-framework"; - -class UnionifyOptions extends MutationOptions {} - -class UnionifyModel extends ModelMutation< - UnionifyOptions, - UnionifyMutations, - SimpleMutationEngine -> { - get unionified() { - return this.getMutatedType(); - } -} - -class UnionifyProperty extends ModelPropertyMutation< - UnionifyOptions, - UnionifyMutations, - SimpleMutationEngine -> { - get unionified() { - return this.getMutatedType(); - } - +class UnionifyProperty extends SimpleModelPropertyMutation { mutate() { if (!this.engine.$.union.is(this.sourceType.type)) { - const unionVariant = this.engine.$.unionVariant.create({ type: this.sourceType.type }); - const fallbackVariant = this.engine.$.unionVariant.create({ - type: this.engine.$.builtin.string, + // Create a union wrapping the original type + const newUnionType = this.engine.$.union.create({ + name: "DynamicUnion", + variants: [ + this.engine.$.unionVariant.create({ type: this.sourceType.type }), + this.engine.$.unionVariant.create({ type: this.engine.$.builtin.string }), + ], }); - const unionType = this.engine.$.union.create({ variants: [unionVariant, fallbackVariant] }); + // Update the mutation node + this.mutationNode.mutate((prop) => { + prop.type = newUnionType; + }); - this.type = this.replaceReferencedType( - this.engine.getDefaultMutationSubgraph(this.options), - unionType, + // Replace and mutate the reference + this.type = this.engine.replaceAndMutateReference( + this.sourceType, + newUnionType, + this.options, + this.startTypeEdge(), ); } else { super.mutate(); } } } +``` -interface UnionifyMutations { - Model: UnionifyModel; - ModelProperty: UnionifyProperty; -} +### Returning Mutations from `mutationInfo` -export function createUnionifyEngine(program: Program) { - const tk = $(program); - return new SimpleMutationEngine(tk, { - Model: UnionifyModel, - ModelProperty: UnionifyProperty, - }); -} +The `mutationInfo` method can return a `Mutation` directly instead of a +`MutationInfo` object. This is useful for completely substituting the mutation +for a different one: -export function unionifyModel(program: Program, fooModel: Model) { - const engine = createUnionifyEngine(program); - const fooMutation = engine.mutate(fooModel, new UnionifyOptions()); - const propMutation = fooMutation.properties.get("prop")!; +```ts +class NullableReferencedModelMutation extends SimpleModelMutation { + static mutationInfo( + engine: SimpleMutationEngine<{ Model: NullableReferencedModelMutation }>, + sourceType: Model, + referenceTypes: MemberType[], + options: SimpleMutationOptions, + halfEdge?: MutationHalfEdge, + traits?: MutationTraits, + ) { + // When accessed via a ModelProperty reference, return a union mutation instead + if (referenceTypes.length > 0 && referenceTypes[0].kind === "ModelProperty") { + const nullableUnion = engine.$.union.create({ + name: `${sourceType.name}NullableUnion`, + variants: [ + engine.$.unionVariant.create({ name: "Value", type: sourceType }), + engine.$.unionVariant.create({ name: "Null", type: engine.$.intrinsic.null }), + ], + }); - return { - property: propMutation.unionified, - model: fooMutation.unionified, - }; + // Return a mutation for the union instead + return engine.replaceAndMutateReference(referenceTypes[0], nullableUnion, options, halfEdge); + } + + return super.mutationInfo(engine, sourceType, referenceTypes, options, halfEdge, traits); + } } ``` -## Core Mutation Base Classes +Mutation nodes also have a `replace` method. Returning a new mutation from MutationInfo makes the resulting Mutations look "as if" the source type graph were shaped differently. This is useful for doing things like normalizations of the type graph. The structure of the Mutations mimic this new structure. When you `replace` on a mutation node, the Mutation stays the same, but the mutated type graph is changed. This is useful for doing things like renaming things or swapping scalars in situations where you want to see both the source type and the mutated type in order to compare them. -| Class | Source Type | Responsibilities | -| ----------------------- | ------------------------------ | ---------------------------------------------------------- | -| `ModelMutation` | `Model` | Traverses base models, properties, and indexers. | -| `ModelPropertyMutation` | `ModelProperty` | Mutates referenced types, exposes `replaceReferencedType`. | -| `UnionMutation` | `Union` | Iterates over variants and lazy-loads their mutations. | -| `UnionVariantMutation` | `UnionVariant` | Handles referenced variant types. | -| `ScalarMutation` | `Scalar` | Provides access to scalar definitions and projections. | -| `LiteralMutation` | string/number/boolean literals | Provides literal values and traversal control. | -| `OperationMutation` | `Operation` | Mutates parameters, return types, and decorators. | -| `InterfaceMutation` | `Interface` | Walks operations declared on the interface. | -| `IntrinsicMutation` | `Intrinsic` | Surfaces intrinsic TypeSpec types. | +## Mutation Caching -Each class inherits from the foundational `Mutation` class, which provides -shared helpers for mutated types (`getMutatedType`) and nodes -(`getMutationNode`). Override them or add convenience getters/setters to tailor -the experience for your consumers. - -## Working with Mutation Subgraphs - -The engine builds mutation nodes inside a `MutationSubgraph`. Each subgraph -captures a set of mutations that share the same options and transformation -logic. +Mutations are automatically cached and reused. When you call `engine.mutate()` +with the same type and options (determined by `mutationKey`), you get back the +same mutation instance: ```ts -const prefixGraph = engine.getPrefix(renameOptions); -const prefixFoo = engine.getMutatedType(prefixGraph, Foo); - -const suffixGraph = engine.getSuffix(renameOptions); -const suffixFoo = engine.getMutatedType(suffixGraph, Foo); +const barMutation = engine.mutate(Bar, new RenameMutationOptions({ suffix: "X" })); +const fooMutation = engine.mutate(Foo, new RenameMutationOptions({ suffix: "X" })); -console.log(prefixFoo.name, suffixFoo.name); +// When traversing from Foo to its Bar property, we get the same mutation +expect(fooMutation.properties.get("prop")!.type === barMutation).toBe(true); ``` -When you call `engine.mutate(type, options)` the engine automatically creates mutation nodes in all -registered subgraphs for the provided options. Subsequent calls reuse the cached nodes, so you can -freely navigate the mutation graph without re-running your transformation logic. +### Simple Mutation Classes + +The `Simple*` mutation classes (e.g., `SimpleModelMutation`, `SimpleModelPropertyMutation`) +are concrete implementations that provide: + +- A `mutationNode` property for accessing the underlying mutation node +- A `mutatedType` property for accessing the mutated TypeSpec type +- `startXEdge()` methods for creating half-edges to connected types ## Tips for Building Mutations - **Always call `super.mutate()`** when you want the default traversal logic after your custom changes. Skipping it gives you full control, but you must handle traversal yourself. -- **Use `MutationOptions` subclasses** whenever your mutation behavior depends on input - configuration. Return a stable `cacheKey()` to reuse work. -- **Inspect `referenceTypes`** to learn which `ModelProperty` or `UnionVariant` led to the current - mutation node. This helps you emit diagnostics or perform context-sensitive logic. -- **Mutate lazily**. Mutations only run once per `(type, options)` pair. If you expose getters that - trigger work, they should go through `engine.mutate(...)` so the cache stays consistent. -- **Prefer `SimpleMutationEngine`** unless you need named subgraphs. You can graduate to a custom - engine later. +- **Use `mutationKey`** to differentiate mutations. Mutations are cached per `(type, mutationKey)` pair. +- **Inspect `referenceTypes`** in `mutationInfo` to learn which `ModelProperty` or `UnionVariant` + led to the current mutation. This enables context-sensitive mutations. +- **Use half-edges** for lazy connections. Call `startXEdge()` and pass the result to `engine.mutate()`. +- **Override `mutationInfo`** to return different mutation keys or substitute mutations entirely. +- **Use `replaceAndMutateReference`** when you need to substitute a type with a synthetic one. ## Additional Resources -- Browse the rest of the files under `packages/mutator-framework/src/mutation` to see the built-in +- Browse the files under `packages/mutator-framework/src/mutation` to see the built-in mutation implementations. -- The unit tests in `mutation-engine.test.ts` demonstrate more end-to-end usage patterns, including - multi-subgraph mutations and reference replacements. +- The unit tests in `simple-mutation-engine.test.ts` demonstrate end-to-end usage patterns, + including custom mutation keys, reference replacements, and type substitutions. diff --git a/packages/mutator-framework/src/mutation-node/enum-member.test.ts b/packages/mutator-framework/src/mutation-node/enum-member.test.ts index 1253f597db1..aebba5340f1 100644 --- a/packages/mutator-framework/src/mutation-node/enum-member.test.ts +++ b/packages/mutator-framework/src/mutation-node/enum-member.test.ts @@ -1,8 +1,8 @@ -import { t, type TesterInstance } from "@typespec/compiler/testing"; +import { expectTypeEquals, t, type TesterInstance } from "@typespec/compiler/testing"; +import { $ } from "@typespec/compiler/typekit"; import { beforeEach, expect, it } from "vitest"; import { Tester } from "../../test/test-host.js"; -import { getSubgraph } from "../../test/utils.js"; - +import { getEngine } from "../../test/utils.js"; let runner: TesterInstance; beforeEach(async () => { runner = await Tester.createInstance(); @@ -16,12 +16,43 @@ it("handles mutation of member values", async () => { } `); - const subgraph = getSubgraph(program); - const fooNode = subgraph.getNode(Foo); - const aNode = subgraph.getNode(a); + const engine = getEngine(program); + const fooNode = engine.getMutationNode(Foo); + const aNode = engine.getMutationNode(a); + fooNode.connectMember(aNode); aNode.mutate((clone) => (clone.value = "valueARenamed")); expect(aNode.isMutated).toBe(true); expect(fooNode.isMutated).toBe(true); - expect(fooNode.mutatedType.members.get("a") === aNode.mutatedType).toBe(true); + expectTypeEquals(fooNode.mutatedType.members.get("a")!, aNode.mutatedType); expect(aNode.mutatedType.value).toBe("valueARenamed"); }); + +it("is deleted when its container enum is deleted", async () => { + const { Foo, prop, program } = await runner.compile(t.code` + enum ${t.enum("Foo")} { + ${t.enumMember("prop")}; + } + `); + const engine = getEngine(program); + const propNode = engine.getMutationNode(prop); + const fooNode = engine.getMutationNode(Foo); + fooNode.connectMember(propNode); + + fooNode.delete(); + expect(propNode.isDeleted).toBe(true); +}); + +it("is deleted when its container enum is replaced", async () => { + const { Foo, prop, program } = await runner.compile(t.code` + enum ${t.enum("Foo")} { + ${t.enumMember("prop")}; + } + `); + const engine = getEngine(program); + const propNode = engine.getMutationNode(prop); + const fooNode = engine.getMutationNode(Foo); + fooNode.connectMember(propNode); + + fooNode.replace($(program).builtin.string); + expect(propNode.isDeleted).toBe(true); +}); diff --git a/packages/mutator-framework/src/mutation-node/enum-member.ts b/packages/mutator-framework/src/mutation-node/enum-member.ts index 7c1bcf73a33..d91c5822a03 100644 --- a/packages/mutator-framework/src/mutation-node/enum-member.ts +++ b/packages/mutator-framework/src/mutation-node/enum-member.ts @@ -1,8 +1,27 @@ -import type { EnumMember } from "@typespec/compiler"; +import type { Enum, EnumMember } from "@typespec/compiler"; +import type { EnumMutationNode } from "./enum.js"; +import { HalfEdge } from "./mutation-edge.js"; import { MutationNode } from "./mutation-node.js"; export class EnumMemberMutationNode extends MutationNode { readonly kind = "EnumMember"; - traverse() {} + startEnumEdge() { + return new HalfEdge(this, { + onTailMutation: ({ tail }) => { + this.mutate(); + this.mutatedType.enum = tail.mutatedType; + }, + onTailDeletion: () => { + this.delete(); + }, + onTailReplaced: ({ head }) => { + head.delete(); + }, + }); + } + + connectEnum(enumNode: EnumMutationNode) { + this.startEnumEdge().setTail(enumNode); + } } diff --git a/packages/mutator-framework/src/mutation-node/enum.test.ts b/packages/mutator-framework/src/mutation-node/enum.test.ts index c89a249d2cf..6fd07e6252c 100644 --- a/packages/mutator-framework/src/mutation-node/enum.test.ts +++ b/packages/mutator-framework/src/mutation-node/enum.test.ts @@ -1,8 +1,7 @@ import { t, type TesterInstance } from "@typespec/compiler/testing"; import { beforeEach, expect, it } from "vitest"; import { Tester } from "../../test/test-host.js"; -import { getSubgraph } from "../../test/utils.js"; - +import { getEngine } from "../../test/utils.js"; let runner: TesterInstance; beforeEach(async () => { runner = await Tester.createInstance(); @@ -16,26 +15,10 @@ it("handles mutation of members", async () => { } `); - const subgraph = getSubgraph(program); - const fooNode = subgraph.getNode(Foo); - const aNode = subgraph.getNode(a); - aNode.mutate(); - expect(aNode.isMutated).toBe(true); - expect(fooNode.isMutated).toBe(true); - expect(fooNode.mutatedType.members.get("a") === aNode.mutatedType).toBe(true); -}); - -it("handles mutation of members with name change", async () => { - const { program, Foo, a } = await runner.compile(t.code` - enum ${t.enum("Foo")} { - ${t.enumMember("a")}; - b; - } - `); - - const subgraph = getSubgraph(program); - const fooNode = subgraph.getNode(Foo); - const aNode = subgraph.getNode(a); + const engine = getEngine(program); + const fooNode = engine.getMutationNode(Foo); + const aNode = engine.getMutationNode(a); + fooNode.connectMember(aNode); aNode.mutate((clone) => (clone.name = "aRenamed")); expect(aNode.isMutated).toBe(true); expect(fooNode.isMutated).toBe(true); @@ -50,10 +33,10 @@ it("handles deletion of members", async () => { b; } `); - - const subgraph = getSubgraph(program); - const fooNode = subgraph.getNode(Foo); - const aNode = subgraph.getNode(a); + const engine = getEngine(program); + const fooNode = engine.getMutationNode(Foo); + const aNode = engine.getMutationNode(a); + fooNode.connectMember(aNode); aNode.delete(); expect(aNode.isDeleted).toBe(true); expect(fooNode.isMutated).toBe(true); diff --git a/packages/mutator-framework/src/mutation-node/enum.ts b/packages/mutator-framework/src/mutation-node/enum.ts index 8a0ee5cfa93..9044ca3a36f 100644 --- a/packages/mutator-framework/src/mutation-node/enum.ts +++ b/packages/mutator-framework/src/mutation-node/enum.ts @@ -1,33 +1,39 @@ import type { Enum, EnumMember } from "@typespec/compiler"; -import { MutationEdge } from "./mutation-edge.js"; +import { HalfEdge } from "./mutation-edge.js"; import { MutationNode } from "./mutation-node.js"; export class EnumMutationNode extends MutationNode { readonly kind = "Enum"; - traverse() { - for (const member of this.sourceType.members.values()) { - const memberNode = this.subgraph.getNode(member); - this.connectMember(memberNode, member.name); - } - } - - connectMember(memberNode: MutationNode, sourcePropName: string) { - MutationEdge.create(this, memberNode, { - onTailMutation: () => { - this.mutatedType.members.delete(sourcePropName); - this.mutatedType.members.set(memberNode.mutatedType.name, memberNode.mutatedType); + startMemberEdge() { + return new HalfEdge(this, { + onTailCreation: ({ tail }) => { + tail.connectEnum(this); + }, + onTailMutation: ({ tail }) => { + this.mutate(); + this.mutatedType.members.delete(tail.sourceType.name); + this.mutatedType.members.set(tail.mutatedType.name, tail.mutatedType); }, - onTailDeletion: () => { - this.mutatedType.members.delete(sourcePropName); + onTailDeletion: ({ tail }) => { + this.mutate(); + this.mutatedType.members.delete(tail.sourceType.name); }, - onTailReplaced: (newTail) => { + onTailReplaced: ({ oldTail, newTail, head, reconnect }) => { if (newTail.mutatedType.kind !== "EnumMember") { throw new Error("Cannot replace enum member with non-enum member type"); } - this.mutatedType.members.delete(sourcePropName); - this.mutatedType.members.set(newTail.mutatedType.name, newTail.mutatedType); + head.mutate(); + head.mutatedType.members.delete(oldTail.sourceType.name); + head.mutatedType.members.set(newTail.mutatedType.name, newTail.mutatedType); + if (reconnect) { + head.connectMember(newTail as MutationNode); + } }, }); } + + connectMember(memberNode: MutationNode) { + this.startMemberEdge().setTail(memberNode); + } } diff --git a/packages/mutator-framework/src/mutation-node/factory.ts b/packages/mutator-framework/src/mutation-node/factory.ts index e8930083d8a..56f39d7d609 100644 --- a/packages/mutator-framework/src/mutation-node/factory.ts +++ b/packages/mutator-framework/src/mutation-node/factory.ts @@ -15,6 +15,7 @@ import type { Union, UnionVariant, } from "@typespec/compiler"; +import type { MutationEngine } from "../mutation/mutation-engine.js"; import { EnumMemberMutationNode } from "./enum-member.js"; import { EnumMutationNode } from "./enum.js"; import { InterfaceMutationNode } from "./interface.js"; @@ -22,7 +23,7 @@ import { IntrinsicMutationNode } from "./intrinsic.js"; import { LiteralMutationNode } from "./literal.js"; import { ModelPropertyMutationNode } from "./model-property.js"; import { ModelMutationNode } from "./model.js"; -import type { MutationSubgraph } from "./mutation-subgraph.js"; +import type { MutationNodeOptions } from "./mutation-node.js"; import { OperationMutationNode } from "./operation.js"; import { ScalarMutationNode } from "./scalar.js"; import { TupleMutationNode } from "./tuple.js"; @@ -30,39 +31,41 @@ import { UnionVariantMutationNode } from "./union-variant.js"; import { UnionMutationNode } from "./union.js"; export function mutationNodeFor( - subgraph: MutationSubgraph, + engine: MutationEngine, sourceType: T, + options?: MutationNodeOptions | string, ): MutationNodeForType { switch (sourceType.kind) { case "Operation": - return new OperationMutationNode(subgraph, sourceType) as MutationNodeForType; + return new OperationMutationNode(engine, sourceType, options) as MutationNodeForType; case "Interface": - return new InterfaceMutationNode(subgraph, sourceType) as MutationNodeForType; + return new InterfaceMutationNode(engine, sourceType, options) as MutationNodeForType; case "Model": - return new ModelMutationNode(subgraph, sourceType) as MutationNodeForType; + return new ModelMutationNode(engine, sourceType, options) as MutationNodeForType; case "ModelProperty": - return new ModelPropertyMutationNode(subgraph, sourceType) as MutationNodeForType; + return new ModelPropertyMutationNode(engine, sourceType, options) as MutationNodeForType; case "Scalar": - return new ScalarMutationNode(subgraph, sourceType) as MutationNodeForType; + return new ScalarMutationNode(engine, sourceType, options) as MutationNodeForType; case "Tuple": - return new TupleMutationNode(subgraph, sourceType) as MutationNodeForType; + return new TupleMutationNode(engine, sourceType, options) as MutationNodeForType; case "Union": - return new UnionMutationNode(subgraph, sourceType) as MutationNodeForType; + return new UnionMutationNode(engine, sourceType, options) as MutationNodeForType; case "UnionVariant": - return new UnionVariantMutationNode(subgraph, sourceType) as MutationNodeForType; + return new UnionVariantMutationNode(engine, sourceType, options) as MutationNodeForType; case "Enum": - return new EnumMutationNode(subgraph, sourceType) as MutationNodeForType; + return new EnumMutationNode(engine, sourceType, options) as MutationNodeForType; case "EnumMember": - return new EnumMemberMutationNode(subgraph, sourceType) as MutationNodeForType; + return new EnumMemberMutationNode(engine, sourceType, options) as MutationNodeForType; case "String": case "Number": case "Boolean": return new LiteralMutationNode( - subgraph, + engine, sourceType as StringLiteral | NumericLiteral | BooleanLiteral, + options, ) as MutationNodeForType; case "Intrinsic": - return new IntrinsicMutationNode(subgraph, sourceType) as MutationNodeForType; + return new IntrinsicMutationNode(engine, sourceType, options) as MutationNodeForType; default: throw new Error("Unsupported type kind: " + sourceType.kind); } diff --git a/packages/mutator-framework/src/mutation-node/index.ts b/packages/mutator-framework/src/mutation-node/index.ts index ec37930f1bf..5934a41831d 100644 --- a/packages/mutator-framework/src/mutation-node/index.ts +++ b/packages/mutator-framework/src/mutation-node/index.ts @@ -2,13 +2,13 @@ export * from "./mutation-node.js"; export * from "./enum-member.js"; export * from "./enum.js"; +export * from "./factory.js"; export * from "./interface.js"; export * from "./intrinsic.js"; export * from "./literal.js"; export * from "./model-property.js"; export * from "./model.js"; export * from "./mutation-edge.js"; -export * from "./mutation-subgraph.js"; export * from "./operation.js"; export * from "./scalar.js"; export * from "./tuple.js"; diff --git a/packages/mutator-framework/src/mutation-node/interface.ts b/packages/mutator-framework/src/mutation-node/interface.ts index 9429a377e69..e4a59ff7897 100644 --- a/packages/mutator-framework/src/mutation-node/interface.ts +++ b/packages/mutator-framework/src/mutation-node/interface.ts @@ -1,33 +1,41 @@ import type { Interface, Operation } from "@typespec/compiler"; -import { MutationEdge } from "./mutation-edge.js"; +import { HalfEdge } from "./mutation-edge.js"; import { MutationNode } from "./mutation-node.js"; +export interface InterfaceConnectOptions { + /** Mutation keys for operation nodes, keyed by operation name. Defaults to this node's key for all. */ + operations?: Record; +} + export class InterfaceMutationNode extends MutationNode { readonly kind = "Interface"; - traverse() { - for (const [opName, op] of this.sourceType.operations) { - const opNode = this.subgraph.getNode(op); - this.connectOperation(opNode, opName); - } - } - - connectOperation(opNode: MutationNode, opName: string) { - MutationEdge.create(this, opNode, { - onTailMutation: () => { - this.mutatedType.operations.delete(opName); - this.mutatedType.operations.set(opNode.mutatedType.name, opNode.mutatedType); + startOperationEdge() { + return new HalfEdge(this, { + onTailCreation: ({ tail }) => { + tail.connectInterface(this); }, - onTailDeletion: () => { - this.mutatedType.operations.delete(opName); + onTailMutation: ({ tail }) => { + this.mutatedType.operations.delete(tail.sourceType.name); + this.mutatedType.operations.set(tail.mutatedType.name, tail.mutatedType); }, - onTailReplaced: (newTail) => { + onTailDeletion: ({ tail }) => { + this.mutatedType.operations.delete(tail.sourceType.name); + }, + onTailReplaced: ({ oldTail, newTail, head, reconnect }) => { if (newTail.mutatedType.kind !== "Operation") { throw new Error("Cannot replace operation with non-operation type"); } - this.mutatedType.operations.delete(opName); - this.mutatedType.operations.set(newTail.mutatedType.name, newTail.mutatedType); + head.mutatedType.operations.delete(oldTail.sourceType.name); + head.mutatedType.operations.set(newTail.mutatedType.name, newTail.mutatedType); + if (reconnect) { + head.connectOperation(newTail as MutationNode); + } }, }); } + + connectOperation(opNode: MutationNode) { + this.startOperationEdge().setTail(opNode); + } } diff --git a/packages/mutator-framework/src/mutation-node/intrinsic.ts b/packages/mutator-framework/src/mutation-node/intrinsic.ts index aca76b7e2c5..18a000ae899 100644 --- a/packages/mutator-framework/src/mutation-node/intrinsic.ts +++ b/packages/mutator-framework/src/mutation-node/intrinsic.ts @@ -4,5 +4,8 @@ import { MutationNode } from "./mutation-node.js"; export class IntrinsicMutationNode extends MutationNode { readonly kind = "Intrinsic"; - traverse() {} + connect() { + if (this.connected) return; + this.connected = true; + } } diff --git a/packages/mutator-framework/src/mutation-node/literal.ts b/packages/mutator-framework/src/mutation-node/literal.ts index 0571cefd02d..a9fced7ffeb 100644 --- a/packages/mutator-framework/src/mutation-node/literal.ts +++ b/packages/mutator-framework/src/mutation-node/literal.ts @@ -6,5 +6,8 @@ export class LiteralMutationNode extends MutationNode< > { readonly kind = "Literal"; - traverse() {} + connect() { + if (this.connected) return; + this.connected = true; + } } diff --git a/packages/mutator-framework/src/mutation-node/model-property.test.ts b/packages/mutator-framework/src/mutation-node/model-property.test.ts index b20b4e805a3..d014ab53e84 100644 --- a/packages/mutator-framework/src/mutation-node/model-property.test.ts +++ b/packages/mutator-framework/src/mutation-node/model-property.test.ts @@ -1,8 +1,9 @@ -import { t, type TesterInstance } from "@typespec/compiler/testing"; +import type { Model } from "@typespec/compiler"; +import { expectTypeEquals, t, type TesterInstance } from "@typespec/compiler/testing"; import { $ } from "@typespec/compiler/typekit"; import { beforeEach, expect, it } from "vitest"; import { Tester } from "../../test/test-host.js"; -import { getSubgraph } from "../../test/utils.js"; +import { getEngine } from "../../test/utils.js"; let runner: TesterInstance; beforeEach(async () => { @@ -15,122 +16,199 @@ it("handles mutation of property types", async () => { ${t.modelProperty("prop")}: string; } `); - const subgraph = getSubgraph(program); - const propNode = subgraph.getNode(prop); - const stringNode = subgraph.getNode($(program).builtin.string); + const engine = getEngine(program); + const propNode = engine.getMutationNode(prop); + const stringNode = engine.getMutationNode($(program).builtin.string); + propNode.connectType(stringNode); stringNode.mutate(); expect(propNode.isMutated).toBe(true); - expect(propNode.mutatedType.type === stringNode.mutatedType).toBe(true); + expectTypeEquals(propNode.mutatedType.type, stringNode.mutatedType); }); -it("handles mutating a reference", async () => { - const { Foo, Bar, prop, program } = await runner.compile(t.code` +it("updates its model property to the mutated model", async () => { + const { Foo, prop, program } = await runner.compile(t.code` + model ${t.model("Foo")} { + ${t.modelProperty("prop")}: string; + } + `); + const engine = getEngine(program); + const propNode = engine.getMutationNode(prop); + const stringNode = engine.getMutationNode($(program).builtin.string); + const fooNode = engine.getMutationNode(Foo); + fooNode.connectProperty(propNode); + propNode.connectType(stringNode); + stringNode.mutate(); + expectTypeEquals(fooNode.mutatedType, propNode.mutatedType.model!); +}); + +it("is deleted when its container model is deleted", async () => { + const { Foo, prop, program } = await runner.compile(t.code` model ${t.model("Foo")} { - ${t.modelProperty("prop")}: Bar; - }; - model ${t.model("Bar")} {} + ${t.modelProperty("prop")}: string; + } `); + const engine = getEngine(program); + const propNode = engine.getMutationNode(prop); + const fooNode = engine.getMutationNode(Foo); + fooNode.connectProperty(propNode); + const stringNode = engine.getMutationNode($(program).builtin.string); + propNode.connectType(stringNode); + fooNode.delete(); + expect(propNode.isDeleted).toBe(true); +}); - const subgraph = getSubgraph(program); - const fooNode = subgraph.getNode(Foo); - const propNode = subgraph.getNode(prop); - const barPrime = subgraph.getReferenceNode(prop); +it("is deleted when its container model is replaced", async () => { + const { Foo, prop, program } = await runner.compile(t.code` + model ${t.model("Foo")} { + ${t.modelProperty("prop")}: string; + } + `); + const engine = getEngine(program); + const propNode = engine.getMutationNode(prop); + const fooNode = engine.getMutationNode(Foo); + fooNode.connectProperty(propNode); + const stringNode = engine.getMutationNode($(program).builtin.string); + propNode.connectType(stringNode); + fooNode.replace($(program).builtin.string); + expect(propNode.isDeleted).toBe(true); +}); - // initially the source type is just Bar. - expect(barPrime.sourceType === Bar).toBe(true); +it("can connect to a different mutation key for the type", async () => { + const { Bar, prop, program } = await runner.compile(t.code` + model Foo { + ${t.modelProperty("prop")}: Bar; + } + model ${t.model("Bar")} {} + `); + const engine = getEngine(program); + const propNode = engine.getMutationNode(prop); + const barNode = engine.getMutationNode(Bar); + + barNode.mutate(); + expect(propNode.isMutated).toBe(false); - barPrime.mutate(); - expect(fooNode.isMutated).toBe(true); + const barNodeCustom = engine.getMutationNode(Bar); + propNode.connectType(barNodeCustom); + barNodeCustom.mutate(); expect(propNode.isMutated).toBe(true); - expect(barPrime.isMutated).toBe(true); - expect(fooNode.mutatedType.properties.get("prop")!.type === barPrime.mutatedType).toBeTruthy(); + expectTypeEquals(propNode.mutatedType.type, barNodeCustom.mutatedType); +}); - const barNode = subgraph.getNode(Bar); +it("can connect to an already-mutated node", async () => { + const { Bar, prop, program } = await runner.compile(t.code` + model Foo { + ${t.modelProperty("prop")}: Bar; + } + + model ${t.model("Bar")} {} + `); + const engine = getEngine(program); + const barNode = engine.getMutationNode(Bar); barNode.mutate(); - expect(barNode.isMutated).toBe(true); - expect(barPrime.isMutated).toBe(true); - // the mutated type doesn't change here. - expect(fooNode.mutatedType.properties.get("prop")!.type === barPrime.mutatedType).toBeTruthy(); + + const propNode = engine.getMutationNode(prop); + propNode.connectType(barNode); + expect(propNode.isMutated).toBe(true); + expectTypeEquals(propNode.mutatedType.type, barNode.mutatedType); }); -it("handles replacing the model reference", async () => { - const { Foo, Bar, prop, program } = await runner.compile(t.code` - model ${t.model("Foo")} { - ${t.modelProperty("prop")}: Bar; - }; - model ${t.model("Bar")} {} - `); - const tk = $(program); - const subgraph = getSubgraph(program); - const fooNode = subgraph.getNode(Foo); - const propNode = subgraph.getNode(prop); - const barPrime = subgraph.getReferenceNode(prop); - const unionType = tk.union.create({ - variants: [ - tk.unionVariant.create({ type: tk.builtin.string }), - tk.unionVariant.create({ type: Bar }), - ], +it("can connect to an already-replaced node", async () => { + const { Bar, prop, program } = await runner.compile(t.code` + model Foo { + ${t.modelProperty("prop")}: Bar; + } + + model ${t.model("Bar")} {} + `); + const engine = getEngine(program); + const barNode = engine.getMutationNode(Bar); + barNode.replace($(program).builtin.int16); + + const propNode = engine.getMutationNode(prop); + propNode.connectType(barNode); + expect(propNode.isMutated).toBe(true); + expectTypeEquals(propNode.mutatedType.type, $(program).builtin.int16); +}); + +it("handles replacing multiple properties", async () => { + const { Foo, one, two, program } = await runner.compile(t.code` + model ${t.model("Foo")} { + ${t.modelProperty("one")}: string; + ${t.modelProperty("two")}: string; + } + `); + + const engine = getEngine(program); + const fooNode = engine.getMutationNode(Foo); + const oneNode = engine.getMutationNode(one); + const twoNode = engine.getMutationNode(two); + fooNode.connectProperty(oneNode); + fooNode.connectProperty(twoNode); + + const r1 = $(program).modelProperty.create({ + name: "replacement", + type: $(program).builtin.string, + }); + const r2 = $(program).modelProperty.create({ + name: "replacement2", + type: $(program).builtin.string, }); + oneNode.replace(r1); + twoNode.replace(r2); - const replacedBarPrime = barPrime.replace(unionType); + expect(fooNode.mutatedType.properties.size).toBe(2); + expect(fooNode.mutatedType.properties.get("replacement")).toBeDefined(); + expect(fooNode.mutatedType.properties.get("replacement2")).toBeDefined(); +}); - // the subgraph now returns the new reference node - expect(subgraph.getReferenceNode(prop) === replacedBarPrime).toBe(true); +it("handles replacing properties and mutating their types", async () => { + const { Foo, Bar, one, program } = await runner.compile(t.code` + model ${t.model("Foo")} { + ${t.modelProperty("one")}: Bar; + } + + model ${t.model("Bar")} {} + `); + + const engine = getEngine(program); + const fooNode = engine.getMutationNode(Foo); + const oneNode = engine.getMutationNode(one); + const barNode = engine.getMutationNode(Bar); + fooNode.connectProperty(oneNode); + oneNode.connectType(barNode); + + const r1 = $(program).modelProperty.create({ + name: "replacement", + type: Bar, + }); + oneNode.replace(r1); - // foo and prop are marked mutated, barPrime is replaced - expect(fooNode.isMutated).toBe(true); - expect(propNode.isMutated).toBe(true); - expect(barPrime.isReplaced).toBe(true); + barNode.mutate(); + barNode.mutatedType.name = "Rebar"; - // prop's type is the replaced type - expect(tk.union.is(propNode.mutatedType.type)).toBe(true); - expect( - fooNode.mutatedType!.properties.get("prop")!.type === replacedBarPrime.mutatedType, - ).toBeTruthy(); + expect(fooNode.mutatedType.properties.size).toBe(1); + expect(fooNode.mutatedType.properties.get("replacement")).toBeDefined(); + expect((fooNode.mutatedType.properties.get("replacement")!.type as Model).name).toBe("Rebar"); }); -it("handles mutating a reference to a reference", async () => { - const { myString, Foo, fprop, Bar, program } = await runner.compile(t.code` - scalar ${t.scalar("myString")} extends string; - model ${t.model("Foo")} { - ${t.modelProperty("fprop")}: myString; - }; - model ${t.model("Bar")} { - bprop: Foo.fprop; - } - `); - - const subgraph = getSubgraph(program); - const fooNode = subgraph.getNode(Foo); - const barNode = subgraph.getNode(Bar); - const myStringNode = subgraph.getNode(myString); - - myStringNode.mutate(); - expect(myStringNode.isMutated).toBe(true); - expect(fooNode.isMutated).toBe(true); - expect(barNode.isMutated).toBe(true); - - // Foo.prop's type is the mutated myString - expect( - fooNode.mutatedType.properties.get("fprop")!.type === myStringNode.mutatedType, - ).toBeTruthy(); - - // Bar.prop's type is the mutated Foo.prop - expect( - barNode.mutatedType.properties.get("bprop")!.type === - fooNode.mutatedType.properties.get("fprop")!, - ).toBeTruthy(); - - const fpropRefNode = subgraph.getReferenceNode(fprop); - fpropRefNode.mutate(); - expect(fpropRefNode.isMutated).toBe(true); - expect( - fooNode.mutatedType.properties.get("fprop")!.type === fpropRefNode.mutatedType, - ).toBeTruthy(); - - // Bar.bprop references the mutated type (though is the same reference since fprop was already mutated) - expect( - barNode.mutatedType.properties.get("bprop")!.type === - fooNode.mutatedType.properties.get("fprop")!, - ).toBeTruthy(); +it("handles replacing properties that have already been mutated", async () => { + const { Foo, one, program } = await runner.compile(t.code` + model ${t.model("Foo")} { + ${t.modelProperty("one")}: string; + } + `); + + const engine = getEngine(program); + const fooNode = engine.getMutationNode(Foo); + const oneNode = engine.getMutationNode(one); + const stringNode = engine.getMutationNode($(program).builtin.string); + oneNode.connectType(stringNode); + const r1 = $(program).modelProperty.create({ + name: "replacement", + type: $(program).builtin.string, + }); + const newNode = oneNode.replace(r1); + fooNode.connectProperty(newNode as any); + expect(fooNode.mutatedType.properties.size).toBe(1); + expect(fooNode.mutatedType.properties.get("replacement")).toBeDefined(); }); diff --git a/packages/mutator-framework/src/mutation-node/model-property.ts b/packages/mutator-framework/src/mutation-node/model-property.ts index c22f4b64400..29025021229 100644 --- a/packages/mutator-framework/src/mutation-node/model-property.ts +++ b/packages/mutator-framework/src/mutation-node/model-property.ts @@ -1,53 +1,66 @@ -import type { ModelProperty, Type } from "@typespec/compiler"; -import { MutationEdge } from "./mutation-edge.js"; +import type { Model, ModelProperty, Type } from "@typespec/compiler"; +import { ModelPropertyMutationNode as SelfType } from "./model-property.js"; +import { HalfEdge } from "./mutation-edge.js"; import { MutationNode } from "./mutation-node.js"; +import { traceNode } from "./tracer.js"; + +export interface ModelPropertyConnectOptions { + /** Mutation key for the property's type node. Defaults to this node's key. */ + typeMutationKey?: string; +} export class ModelPropertyMutationNode extends MutationNode { readonly kind = "ModelProperty"; - #referenceMutated = false; - - traverse() { - const typeNode = this.subgraph.getNode(this.sourceType.type); - const referenceNode = this.subgraph.getReferenceNode(this.sourceType); - - this.connectType(typeNode); - this.connectReference(referenceNode); - } - connectReference(referenceNode: MutationNode) { - MutationEdge.create(this, referenceNode, { - onTailMutation: () => { - this.#referenceMutated = true; - this.mutatedType.type = referenceNode.mutatedType; + startTypeEdge() { + return new HalfEdge(this, { + onTailMutation: ({ tail }) => { + traceNode(this, "Model property type mutated."); + this.mutate(); + this.mutatedType.type = tail.mutatedType; }, - onTailDeletion: () => { - this.#referenceMutated = true; + onTailDeletion: (_args) => { + this.mutate(); this.mutatedType.type = this.$.intrinsic.any; }, - onTailReplaced: (newTail) => { - this.#referenceMutated = true; - this.mutatedType.type = newTail.mutatedType; + onTailReplaced: ({ newTail, head, reconnect }) => { + head.mutate(); + head.mutatedType.type = newTail.mutatedType; + if (reconnect) { + (head as ModelPropertyMutationNode).connectType(newTail); + } + }, + onHeadReplaced: ({ newHead, tail }) => { + // When this edge's head is replaced, have the new head establish + // its own connection to the tail so it receives future mutations + if (newHead instanceof SelfType) { + (newHead as ModelPropertyMutationNode).connectType(tail); + } }, }); } connectType(typeNode: MutationNode) { - MutationEdge.create(this, typeNode, { - onTailMutation: () => { - if (this.#referenceMutated) { - return; - } - this.mutatedType.type = typeNode.mutatedType; + this.startTypeEdge().setTail(typeNode); + } + + startModelEdge() { + return new HalfEdge(this, { + onTailMutation: ({ tail }) => { + traceNode(this, "Model property model mutated."); + this.mutate(); + this.mutatedType.model = tail.mutatedType; }, onTailDeletion: () => { - if (this.#referenceMutated) { - return; - } - this.mutatedType.type = this.$.intrinsic.any; + this.delete(); }, - onTailReplaced: (newTail) => { - this.mutatedType.type = newTail.mutatedType; + onTailReplaced: ({ head }) => { + head.delete(); }, }); } + + connectModel(modelNode: MutationNode) { + this.startModelEdge().setTail(modelNode); + } } diff --git a/packages/mutator-framework/src/mutation-node/model.test.ts b/packages/mutator-framework/src/mutation-node/model.test.ts index b68eb927968..ebd4892d2e5 100644 --- a/packages/mutator-framework/src/mutation-node/model.test.ts +++ b/packages/mutator-framework/src/mutation-node/model.test.ts @@ -1,8 +1,8 @@ import type { Model, Type } from "@typespec/compiler"; -import { t, type TesterInstance } from "@typespec/compiler/testing"; +import { expectTypeEquals, t, type TesterInstance } from "@typespec/compiler/testing"; import { beforeEach, expect, it } from "vitest"; import { Tester } from "../../test/test-host.js"; -import { getSubgraph } from "../../test/utils.js"; +import { getEngine } from "../../test/utils.js"; let runner: TesterInstance; beforeEach(async () => { @@ -15,12 +15,30 @@ it("handles mutation of properties", async () => { prop: string; } `); - const subgraph = getSubgraph(program); - const fooNode = subgraph.getNode(Foo); - const propNode = subgraph.getNode(Foo.properties.get("prop")!); + const engine = getEngine(program); + const fooNode = engine.getMutationNode(Foo); + const propNode = engine.getMutationNode(Foo.properties.get("prop")!); + fooNode.connectProperty(propNode); propNode.mutate(); expect(fooNode.isMutated).toBe(true); - expect(fooNode.mutatedType.properties.get("prop") === propNode.mutatedType).toBe(true); + expectTypeEquals(fooNode.mutatedType.properties.get("prop")!, propNode.mutatedType); +}); + +it("handles mutation of properties lazily", async () => { + const { Foo, program } = await runner.compile(t.code` + model ${t.model("Foo")} { + prop: string; + } + `); + const engine = getEngine(program); + const fooNode = engine.getMutationNode(Foo); + fooNode.mutate(); + + const propNode = engine.getMutationNode(Foo.properties.get("prop")!); + fooNode.connectProperty(propNode); + expect(fooNode.isMutated).toBe(true); + expect(propNode.isMutated).toBe(true); + expectTypeEquals(fooNode.mutatedType.properties.get("prop")!, propNode.mutatedType); }); it("handles deletion of properties", async () => { @@ -29,9 +47,10 @@ it("handles deletion of properties", async () => { prop: string; } `); - const subgraph = getSubgraph(program); - const fooNode = subgraph.getNode(Foo); - const propNode = subgraph.getNode(Foo.properties.get("prop")!); + const engine = getEngine(program); + const fooNode = engine.getMutationNode(Foo); + const propNode = engine.getMutationNode(Foo.properties.get("prop")!); + fooNode.connectProperty(propNode); propNode.delete(); expect(fooNode.isMutated).toBe(true); expect(fooNode.mutatedType.properties.get("prop")).toBeUndefined(); @@ -43,13 +62,14 @@ it("handles mutation of properties with name change", async () => { prop: string; } `); - const subgraph = getSubgraph(program); - const fooNode = subgraph.getNode(Foo); - const propNode = subgraph.getNode(Foo.properties.get("prop")!); + const engine = getEngine(program); + const fooNode = engine.getMutationNode(Foo); + const propNode = engine.getMutationNode(Foo.properties.get("prop")!); + fooNode.connectProperty(propNode); propNode.mutate((clone) => (clone.name = "propRenamed")); expect(fooNode.isMutated).toBe(true); - expect(fooNode.mutatedType.properties.get("prop") === undefined).toBe(true); - expect(fooNode.mutatedType.properties.get("propRenamed") === propNode.mutatedType).toBe(true); + expect(fooNode.mutatedType.properties.get("prop")).toBeUndefined(); + expectTypeEquals(fooNode.mutatedType.properties.get("propRenamed")!, propNode.mutatedType); }); it("handles mutation of base models", async () => { @@ -62,10 +82,10 @@ it("handles mutation of base models", async () => { bazProp: string; } `); - const subgraph = getSubgraph(program); - const fooNode = subgraph.getNode(Foo); - const barNode = subgraph.getNode(Bar); - + const engine = getEngine(program); + const fooNode = engine.getMutationNode(Foo); + const barNode = engine.getMutationNode(Bar); + fooNode.connectBase(barNode); barNode.mutate(); expect(barNode.isMutated).toBe(true); expect(fooNode.isMutated).toBe(true); @@ -82,9 +102,10 @@ it("handles deletion of base models", async () => { bazProp: string; } `); - const subgraph = getSubgraph(program); - const fooNode = subgraph.getNode(Foo); - const barNode = subgraph.getNode(Bar); + const engine = getEngine(program); + const fooNode = engine.getMutationNode(Foo); + const barNode = engine.getMutationNode(Bar); + fooNode.connectBase(barNode); barNode.delete(); expect(barNode.isDeleted).toBe(true); @@ -99,9 +120,10 @@ it("handles mutation of indexers", async () => { bazProp: string; } `); - const subgraph = getSubgraph(program); - const fooNode = subgraph.getNode(Foo); - const barNode = subgraph.getNode(Bar); + const engine = getEngine(program); + const fooNode = engine.getMutationNode(Foo); + const barNode = engine.getMutationNode(Bar); + fooNode.connectIndexerValue(barNode); barNode.mutate(); expect(barNode.isMutated).toBe(true); @@ -117,10 +139,15 @@ it("handles mutation of arrays", async () => { } `); - const subgraph = getSubgraph(program); - const fooNode = subgraph.getNode(Foo); - const barNode = subgraph.getNode(Bar); - const bazPropNode = subgraph.getNode(bazProp); + const engine = getEngine(program); + const fooNode = engine.getMutationNode(Foo); + const barNode = engine.getMutationNode(Bar); + const bazPropNode = engine.getMutationNode(bazProp); + barNode.connectProperty(bazPropNode); + const arrayType = bazProp.type as Model; + const arrayNode = engine.getMutationNode(arrayType); + bazPropNode.connectType(arrayNode); + arrayNode.connectIndexerValue(fooNode); fooNode.mutate(); expect(fooNode.isMutated).toBe(true); @@ -141,9 +168,15 @@ it("handles circular models", async () => { } `); - const subgraph = getSubgraph(program); - const fooNode = subgraph.getNode(Foo); - const barNode = subgraph.getNode(Bar); + const engine = getEngine(program); + const fooNode = engine.getMutationNode(Foo); + const barNode = engine.getMutationNode(Bar); + const fooPropBar = engine.getMutationNode(Foo.properties.get("bar")!); + const barPropFoo = engine.getMutationNode(Bar.properties.get("foo")!); + fooNode.connectProperty(fooPropBar); + fooPropBar.connectType(barNode); + barNode.connectProperty(barPropFoo); + barPropFoo.connectType(fooNode); fooNode.mutate(); expect(fooNode.isMutated).toBe(true); diff --git a/packages/mutator-framework/src/mutation-node/model.ts b/packages/mutator-framework/src/mutation-node/model.ts index 742550f46b1..895e7d15253 100644 --- a/packages/mutator-framework/src/mutation-node/model.ts +++ b/packages/mutator-framework/src/mutation-node/model.ts @@ -1,74 +1,97 @@ -import type { Model, ModelProperty, Type } from "@typespec/compiler"; -import { MutationEdge } from "./mutation-edge.js"; +import type { Model, ModelProperty, Scalar, Type } from "@typespec/compiler"; +import type { ModelPropertyMutationNode } from "./model-property.js"; +import { HalfEdge } from "./mutation-edge.js"; import { MutationNode } from "./mutation-node.js"; +import { traceNode } from "./tracer.js"; + +export interface ModelConnectOptions { + /** Mutation key for the base model node. Defaults to this node's key. */ + baseModel?: string; + /** Mutation key for the indexer value node. Defaults to this node's key. */ + indexerValue?: string; +} export class ModelMutationNode extends MutationNode { readonly kind = "Model"; - - traverse() { - if (this.sourceType.baseModel) { - const baseNode = this.subgraph.getNode(this.sourceType.baseModel); - this.connectToBase(baseNode); - } - - for (const [propName, prop] of this.sourceType.properties) { - const propNode = this.subgraph.getNode(prop); - this.connectProperty(propNode, propName); - } - - if (this.sourceType.indexer) { - const indexerNode = this.subgraph.getNode(this.sourceType.indexer.value); - this.connectIndexerValue(indexerNode); - } - } - - connectToBase(baseNode: MutationNode) { - MutationEdge.create(this, baseNode, { - onTailMutation: () => { - this.mutatedType!.baseModel = baseNode.mutatedType; + startBaseModelEdge() { + return new HalfEdge(this, { + onTailMutation: ({ tail }) => { + this.mutate(); + this.mutatedType!.baseModel = tail.mutatedType; }, onTailDeletion: () => { + this.mutate(); this.mutatedType.baseModel = undefined; }, - onTailReplaced: (newTail) => { + onTailReplaced: ({ newTail, head, reconnect }) => { if (newTail.mutatedType.kind !== "Model") { throw new Error("Cannot replace base model with non-model type"); } - this.mutatedType.baseModel = newTail.mutatedType; + head.mutate(); + head.mutatedType.baseModel = newTail.mutatedType; + if (reconnect) { + head.connectBase(newTail as MutationNode); + } }, }); } + connectBase(baseNode: MutationNode) { + this.startBaseModelEdge().setTail(baseNode); + } - connectProperty(propNode: MutationNode, sourcePropName: string) { - MutationEdge.create(this, propNode, { - onTailMutation: () => { - this.mutatedType.properties.delete(sourcePropName); - this.mutatedType.properties.set(propNode.mutatedType.name, propNode.mutatedType); + startPropertyEdge() { + return new HalfEdge(this, { + onTailCreation: ({ tail }) => { + tail.connectModel(this); }, - onTailDeletion: () => { - this.mutatedType.properties.delete(sourcePropName); + onTailMutation: ({ tail }) => { + this.mutate(); + traceNode( + this, + `Model property mutated: ${tail.sourceType.name} -> ${tail.mutatedType.name}`, + ); + this.mutatedType.properties.delete(tail.sourceType.name); + this.mutatedType.properties.set(tail.mutatedType.name, tail.mutatedType); + }, + onTailDeletion: ({ tail }) => { + this.mutate(); + this.mutatedType.properties.delete(tail.sourceType.name); }, - onTailReplaced: (newTail) => { + onTailReplaced: ({ oldTail, newTail, head, reconnect }) => { if (newTail.mutatedType.kind !== "ModelProperty") { throw new Error("Cannot replace model property with non-model property type"); } - this.mutatedType.properties.delete(sourcePropName); - this.mutatedType.properties.set(newTail.mutatedType.name, newTail.mutatedType); + head.mutate(); + traceNode( + this, + `Model property replaced: ${oldTail.sourceType.name} -> ${newTail.mutatedType.name}`, + ); + head.mutatedType.properties.delete(oldTail.sourceType.name); + head.mutatedType.properties.set(newTail.mutatedType.name, newTail.mutatedType); + if (reconnect) { + head.connectProperty(newTail as unknown as ModelPropertyMutationNode); + } }, }); } - connectIndexerValue(indexerNode: MutationNode) { - MutationEdge.create(this, indexerNode, { - onTailMutation: () => { + connectProperty(propNode: ModelPropertyMutationNode) { + this.startPropertyEdge().setTail(propNode); + } + + startIndexerValueEdge() { + return new HalfEdge(this, { + onTailMutation: ({ tail }) => { + this.mutate(); if (this.mutatedType.indexer) { this.mutatedType.indexer = { key: this.mutatedType.indexer.key, - value: indexerNode.mutatedType, + value: tail.mutatedType, }; } }, onTailDeletion: () => { + this.mutate(); if (this.mutatedType.indexer) { this.mutatedType.indexer = { key: this.mutatedType.indexer.key, @@ -76,14 +99,64 @@ export class ModelMutationNode extends MutationNode { }; } }, - onTailReplaced: (newTail) => { + onTailReplaced: ({ newTail, head, reconnect }) => { + head.mutate(); + if (head.mutatedType.indexer) { + head.mutatedType.indexer = { + key: head.mutatedType.indexer.key, + value: newTail.mutatedType, + }; + } + if (reconnect) { + head.connectIndexerValue(newTail); + } + }, + }); + } + + startIndexerKeyEdge() { + return new HalfEdge(this, { + onTailMutation: ({ tail }) => { + this.mutate(); if (this.mutatedType.indexer) { this.mutatedType.indexer = { - key: this.mutatedType.indexer.key, - value: newTail.mutatedType, + key: tail.mutatedType, + value: this.mutatedType.indexer.value, + }; + } + }, + onTailDeletion: () => { + this.mutate(); + if (this.mutatedType.indexer) { + this.mutatedType.indexer = { + key: this.$.builtin.integer, + value: this.mutatedType.indexer.value, }; } }, + onTailReplaced: ({ newTail, head, reconnect }) => { + if (!head.$.scalar.is(newTail.mutatedType)) { + throw new Error("Cannot replace indexer key with non-scalar type"); + } + head.mutate(); + if (head.mutatedType.indexer) { + head.mutatedType.indexer = { + key: newTail.mutatedType, + value: head.mutatedType.indexer.value, + }; + } + if (reconnect) { + head.connectIndexerKey(newTail as MutationNode); + } + }, }); } + + connectIndexerKey(indexerNode: MutationNode) { + this.startIndexerKeyEdge().setTail(indexerNode); + } + + connectIndexerValue(indexerNode: MutationNode) { + this.startIndexerValueEdge().setTail(indexerNode); + } } diff --git a/packages/mutator-framework/src/mutation-node/mutation-edge.ts b/packages/mutator-framework/src/mutation-node/mutation-edge.ts index 3c537ce8970..64866e61978 100644 --- a/packages/mutator-framework/src/mutation-node/mutation-edge.ts +++ b/packages/mutator-framework/src/mutation-node/mutation-edge.ts @@ -1,43 +1,157 @@ import type { Type } from "@typespec/compiler"; +import type { MutationNodeForType } from "./factory.js"; import { MutationNode } from "./mutation-node.js"; +import { traceEdge } from "./tracer.js"; -export interface MutationEdgeOptions { - onTailMutation: () => void; - onTailDeletion: () => void; - onTailReplaced: (newTail: MutationNode) => void; +export interface MutationEdgeOptions { + onTailCreation?: (args: { tail: MutationNodeForType }) => void; + onTailMutation: (args: { tail: MutationNodeForType }) => void; + onTailDeletion: (args: { tail: MutationNodeForType }) => void; + /** + * Called when the tail node is replaced with a new node. + * @param args.oldTail - The original tail node that was replaced + * @param args.newTail - The new tail node + * @param args.head - The head node of this edge + * @param args.reconnect - If true, the callback should create a new edge to newTail. + * If false, an edge already exists and should not be recreated. + */ + onTailReplaced: (args: { + oldTail: MutationNodeForType; + newTail: MutationNodeForType; + head: MutationNodeForType; + reconnect: boolean; + }) => void; + onHeadReplaced?: (args: { + oldHead: MutationNodeForType; + newHead: MutationNodeForType; + tail: MutationNodeForType; + }) => void; } export class MutationEdge { public head: MutationNode; public tail: MutationNode; - #options: MutationEdgeOptions; + #options: MutationEdgeOptions; + #deleted: boolean = false; - constructor(head: MutationNode, tail: MutationNode, options: MutationEdgeOptions) { + constructor( + head: MutationNode, + tail: MutationNode, + options: MutationEdgeOptions, + ) { this.head = head; this.tail = tail; this.#options = options; + traceEdge(this, "Created."); this.tail.addInEdge(this); + this.head.addOutEdge(this); + + // If the tail is a replacement node, notify the head about the replacement + // so it can update its state (e.g., delete old property name, add new one). + // We don't delete this edge since it's already correctly pointing to the new tail. + // Pass reconnect=false since the edge already exists. + if (this.tail.replacedNode) { + traceEdge(this, "Tail is a replacement node, notifying head."); + this.#options.onTailReplaced({ + oldTail: this.tail.replacedNode as any, + newTail: this.tail as any, + head: this.head as any, + reconnect: false, // don't reconnect - edge already exists + }); + } else if (this.tail.isMutated || this.tail.isSynthetic) { + this.tailMutated(); + } + + if (this.tail.isReplaced) { + this.tailReplaced(this.tail.replacementNode!); + } } - static create(head: MutationNode, tail: MutationNode, options: MutationEdgeOptions) { + static create( + head: MutationNode, + tail: MutationNode, + options: MutationEdgeOptions, + ) { return new MutationEdge(head, tail, options); } + /** + * Delete this edge, removing it from both the head's outEdges and tail's inEdges. + * Once deleted, the edge will no longer propagate any mutations. + */ + delete() { + if (this.#deleted) return; + traceEdge(this, "Deleted."); + this.#deleted = true; + this.head.deleteOutEdge(this); + this.tail.deleteInEdge(this); + } + tailMutated(): void { - this.head.mutate(); - this.#options.onTailMutation(); + if (this.#deleted || this.head.isDeleted) return; + traceEdge(this, "Tail mutated."); + this.#options.onTailMutation({ tail: this.tail as any }); } tailDeleted() { - this.head.mutate(); - this.#options.onTailDeletion(); + if (this.#deleted || this.head.isDeleted) return; + traceEdge(this, "Tail deleted."); + this.#options.onTailDeletion({ tail: this.tail as any }); } - tailReplaced(newTail: MutationNode) { - this.head.mutate(); - this.tail.deleteInEdge(this); - this.tail = newTail; - this.tail.addInEdge(this); - this.#options.onTailReplaced(newTail); + tailReplaced(newTail: MutationNode, oldTail?: MutationNode) { + if (this.#deleted || this.head.isDeleted) return; + traceEdge(this, "Tail replaced with " + newTail.id); + const actualOldTail = oldTail ?? this.tail; + const head = this.head; + // Delete this edge - the onTailReplaced callback is responsible for + // creating a new edge if the head node needs to track the new tail's mutations + this.delete(); + this.#options.onTailReplaced({ + oldTail: actualOldTail as any, + newTail: newTail as any, + head: head as any, + reconnect: true, + }); + } + + headReplaced(newHead: MutationNode) { + if (this.#deleted || this.tail.isDeleted) return; + traceEdge(this, "Head replaced with " + newHead.id); + const oldHead = this.head; + const tail = this.tail; + // Delete this edge - the onHeadReplaced callback is responsible for + // creating a new edge if the replacement node needs to track tail mutations + this.delete(); + this.#options.onHeadReplaced?.({ + oldHead: oldHead as any, + newHead: newHead as any, + tail: tail as any, + }); + } + + toString() { + return `MutationEdge(head=${this.head.id}, tail=${this.tail.id})`; + } +} + +export class HalfEdge { + public head: MutationNode; + public tail: MutationNode | null; + #options: MutationEdgeOptions; + + constructor(head: MutationNode, options: MutationEdgeOptions) { + this.head = head; + this.tail = null; + this.#options = options; + } + + setTail(tail: MutationNode): MutationEdge { + if (this.tail) { + throw new Error("HalfEdge already has a tail"); + } + this.tail = tail; + this.#options.onTailCreation?.({ tail: tail as any }); + return MutationEdge.create(this.head, this.tail, this.#options); } } diff --git a/packages/mutator-framework/src/mutation-node/mutation-node.test.ts b/packages/mutator-framework/src/mutation-node/mutation-node.test.ts index f39c4405186..8dda9ffcbfc 100644 --- a/packages/mutator-framework/src/mutation-node/mutation-node.test.ts +++ b/packages/mutator-framework/src/mutation-node/mutation-node.test.ts @@ -1,57 +1,36 @@ -import { t, type TesterInstance } from "@typespec/compiler/testing"; +import { expectTypeEquals, t, type TesterInstance } from "@typespec/compiler/testing"; +import { $ } from "@typespec/compiler/typekit"; import { beforeEach, expect, it } from "vitest"; import { Tester } from "../../test/test-host.js"; -import { getSubgraph } from "../../test/utils.js"; +import { getEngine } from "../../test/utils.js"; let runner: TesterInstance; beforeEach(async () => { runner = await Tester.createInstance(); }); -it("Subgraph#getNode returns the same node for the same type when called", async () => { +it("Engine#getMutationNode returns the same node for the same type when called", async () => { const { Foo, program } = await runner.compile(t.code` model ${t.model("Foo")} { prop: string; } `); - const subgraph = getSubgraph(program); - const fooNode1 = subgraph.getNode(Foo); - const fooNode2 = subgraph.getNode(Foo); + const engine = getEngine(program); + const fooNode1 = engine.getMutationNode(Foo); + const fooNode2 = engine.getMutationNode(Foo); expect(fooNode1 === fooNode2).toBe(true); }); -it("Creates the same node when constructing the subgraph and coming back to the same type", async () => { - const { Foo, Bar, Baz, program } = await runner.compile(t.code` - model ${t.model("Foo")} { - prop: string; - } - - model ${t.model("Bar")} { - foo: Foo; - } - - model ${t.model("Baz")} { - foo: Foo; - } - `); - const subgraph = getSubgraph(program); - const fooNode = subgraph.getNode(Foo); - subgraph.getNode(Bar); - subgraph.getNode(Baz); - - expect(fooNode.inEdges.size).toBe(2); -}); - it("starts with the mutatedType and sourceType being the same", async () => { const { Foo, program } = await runner.compile(t.code` model ${t.model("Foo")} { prop: string; } `); - const subgraph = getSubgraph(program); - const fooNode = subgraph.getNode(Foo); + const engine = getEngine(program); + const fooNode = engine.getMutationNode(Foo); expect(fooNode.isMutated).toBe(false); - expect(fooNode.sourceType === fooNode.mutatedType).toBe(true); + expectTypeEquals(fooNode.sourceType, fooNode.mutatedType); }); it("clones the source type when mutating and sets isMutated to true", async () => { @@ -60,10 +39,10 @@ it("clones the source type when mutating and sets isMutated to true", async () = prop: string; } `); - const subgraph = getSubgraph(program); - const fooNode = subgraph.getNode(Foo); + const engine = getEngine(program); + const fooNode = engine.getMutationNode(Foo); expect(fooNode.isMutated).toBe(false); - expect(fooNode.sourceType === fooNode.mutatedType).toBe(true); + expectTypeEquals(fooNode.sourceType, fooNode.mutatedType); fooNode.mutate(); expect(fooNode.isMutated).toBe(true); expect(fooNode.sourceType === fooNode.mutatedType).toBe(false); @@ -71,7 +50,7 @@ it("clones the source type when mutating and sets isMutated to true", async () = }); it("invokes whenMutated callbacks when mutating", async () => { - const { Foo, program } = await runner.compile(t.code` + const { Foo, Bar, program } = await runner.compile(t.code` model ${t.model("Foo")} { prop: Bar; } @@ -80,9 +59,12 @@ it("invokes whenMutated callbacks when mutating", async () => { prop: string; } `); - const subgraph = getSubgraph(program); - const fooNode = subgraph.getNode(Foo); - const barNode = subgraph.getNode(Foo); + const engine = getEngine(program); + const fooNode = engine.getMutationNode(Foo); + const barNode = engine.getMutationNode(Bar); + const fooProp = engine.getMutationNode(Foo.properties.get("prop")!); + fooNode.connectProperty(fooProp); + fooProp.connectType(barNode); let called = false; fooNode.whenMutated((mutatedType) => { called = true; @@ -92,3 +74,38 @@ it("invokes whenMutated callbacks when mutating", async () => { barNode.mutate(); expect(called).toBe(true); }); + +it("clones synthetic mutation nodes", async () => { + const { Foo, prop, program } = await runner.compile(t.code` + model ${t.model("Foo")} { + ${t.modelProperty("prop")}: string; + } + `); + const engine = getEngine(program); + const fooNode = engine.getMutationNode(Foo); + const propNode = engine.getMutationNode(prop); + fooNode.connectProperty(propNode); + + const model = $(program).model.create({ + name: "Testing", + properties: {}, + }); + + const typeNode = engine.getMutationNode(model, { isSynthetic: true }); + propNode.connectType(typeNode); + + // the type isn't mutated + expect(typeNode.isMutated).toBe(false); + + // but things referencing it are... + expect(propNode.isMutated).toBe(true); + expect(fooNode.isMutated).toBe(true); + + // we haven't mutated anything yet. + expect(propNode.mutatedType.type === model).toBe(true); + + typeNode.mutate(); + expect(typeNode.isMutated).toBe(true); + expect(propNode.mutatedType.type === model).toBe(false); + expect(propNode.mutatedType.type === typeNode.mutatedType).toBe(true); +}); diff --git a/packages/mutator-framework/src/mutation-node/mutation-node.ts b/packages/mutator-framework/src/mutation-node/mutation-node.ts index d855c151c9e..f4dbaa6478a 100644 --- a/packages/mutator-framework/src/mutation-node/mutation-node.ts +++ b/packages/mutator-framework/src/mutation-node/mutation-node.ts @@ -1,11 +1,35 @@ -import type { MemberType, Type } from "@typespec/compiler"; +import type { Type } from "@typespec/compiler"; import type { Typekit } from "@typespec/compiler/typekit"; +import type { MutationEngine } from "../mutation/mutation-engine.js"; import { mutationNodeFor, type MutationNodeForType } from "./factory.js"; import type { MutationEdge } from "./mutation-edge.js"; -import type { MutationSubgraph } from "./mutation-subgraph.js"; +import { traceNode } from "./tracer.js"; + +/** + * Mutation nodes represent a node in the type graph that can possibly be + * mutated. Each mutation node tracks the source type, the mutated type, and the + * edges coming from other mutation nodes which represent references to the + * source type for this node. + * + * The mutated type is initially a reference to the source type. When a node is + * mutated, the mutated type is initialized to a clone of the source type and + * any mutations are applied. Then all nodes which reference this node are also + * mutated, which will cause their mutated types to reference the mutated type + * of this node. + * + * Each node is unique based on the source type and an optional mutation key. + * The mutation key allows for multiple mutation nodes to exist for the same + * source type, which is useful when a type's mutation depends on its context + * such as how it is referenced. + */ let nextId = 0; +export interface MutationNodeOptions { + mutationKey?: string; + isSynthetic?: boolean; +} + export abstract class MutationNode { abstract readonly kind: string; @@ -13,43 +37,76 @@ export abstract class MutationNode { sourceType: T; mutatedType: T; isMutated: boolean = false; + isSynthetic: boolean = false; isDeleted: boolean = false; isReplaced: boolean = false; replacementNode: MutationNodeForType | null = null; - inEdges: Set> = new Set(); - subgraph: MutationSubgraph; - referenceType: MemberType | null = null; + /** If this node is a replacement for another node, this is the node it replaced */ + replacedNode: MutationNodeForType | null = null; + inEdges: Set> = new Set(); + outEdges: Set> = new Set(); + engine: MutationEngine; + mutationKey: string; $: Typekit; + protected connected: boolean = false; #whenMutatedCallbacks: ((mutatedType: Type | null) => void)[] = []; - constructor(subgraph: MutationSubgraph, sourceNode: T) { - this.subgraph = subgraph; - this.$ = this.subgraph.engine.$; + constructor( + subgraph: MutationEngine, + sourceNode: T, + options: MutationNodeOptions | string = "", + ) { + this.engine = subgraph; + this.$ = this.engine.$; this.sourceType = sourceNode; this.mutatedType = sourceNode; - } + if (typeof options === "string") { + this.mutationKey = options; + } else { + this.mutationKey = options.mutationKey ?? ""; + this.isSynthetic = options.isSynthetic ?? false; + } - abstract traverse(): void; + traceNode(this, "Created."); + } - addInEdge(edge: MutationEdge) { + addInEdge(edge: MutationEdge) { this.inEdges.add(edge); } - deleteInEdge(edge: MutationEdge) { + deleteInEdge(edge: MutationEdge) { this.inEdges.delete(edge); } + addOutEdge(edge: MutationEdge) { + this.outEdges.add(edge); + } + + deleteOutEdge(edge: MutationEdge) { + this.outEdges.delete(edge); + } + whenMutated(cb: (mutatedType: T | null) => void) { this.#whenMutatedCallbacks.push(cb as any); } mutate(initializeMutation?: (type: T) => void) { - if (this.isMutated || this.isDeleted || this.isReplaced) { + if (this.isDeleted || this.isReplaced) { + traceNode(this, `Already deleted/replaced, skipping mutation.`); return; } + if (this.isMutated) { + traceNode(this, "Already mutated, running initialization"); + initializeMutation?.(this.mutatedType); + return; + } + + traceNode(this, "Mutating."); + this.mutatedType = this.$.type.clone(this.sourceType); + this.isMutated = true; initializeMutation?.(this.mutatedType); for (const cb of this.#whenMutatedCallbacks) { @@ -64,9 +121,7 @@ export abstract class MutationNode { } delete() { - if (this.isMutated || this.isDeleted || this.isReplaced) { - return; - } + traceNode(this, "Deleting."); this.isDeleted = true; @@ -81,30 +136,56 @@ export abstract class MutationNode { } } + /** + * Replace this node with a new type. This creates a new mutation node for the + * replacement type and updates all edges to point to the new node. + * + * When a node is replaced: + * 1. A new mutation node is created for the replacement type + * 2. The original node is marked as replaced and will ignore future mutations + * 3. All out-edges (where this node is the head) are notified via `headReplaced`, + * which marks the edge so its callbacks no longer fire for the original node. + * The edge's `onHeadReplaced` callback is invoked, allowing the replacement + * node to establish its own connections to the tail nodes if needed. + * 4. All in-edges (where this node is the tail) are notified via `tailReplaced`, + * which updates the edge to point to the replacement node and invokes the + * head's `onTailReplaced` callback. + * + * @param newType - The type to replace this node with + * @returns The new mutation node for the replacement type + */ replace(newType: Type) { - if (this.isMutated || this.isDeleted || this.isReplaced) { + if (this.isReplaced) { return this; } + traceNode(this, "Replacing."); + // We need to make a new node because different types need to handle edge mutations differently. this.isReplaced = true; - this.replacementNode = mutationNodeFor(this.subgraph, newType); - this.replacementNode.traverse(); + this.replacementNode = mutationNodeFor(this.engine, newType, this.mutationKey); + // Set the back-reference so the replacement node knows what it replaced + this.replacementNode.replacedNode = this as unknown as MutationNodeForType; // we don't need to do the clone stuff with this node, but we mark it as // mutated because we don't want to allow further mutations on it. this.replacementNode.isMutated = true; - if (this.referenceType) { - this.subgraph.replaceReferenceNode(this.referenceType, this.replacementNode); - } else { - this.subgraph.replaceNode(this, this.replacementNode); + this.engine.replaceMutationNode(this, this.replacementNode); + traceNode(this, "Calling head replaced"); + for (const edge of this.outEdges) { + edge.headReplaced(this.replacementNode); } + traceNode(this, "Calling tail replaced"); for (const edge of this.inEdges) { edge.tailReplaced(this.replacementNode); } return this.replacementNode; } + + toString() { + return `MutationNode(${"name" in this.sourceType && typeof this.sourceType.name === "string" ? this.sourceType.name : this.kind}, key=${this.mutationKey}, id=${this.id})`; + } } diff --git a/packages/mutator-framework/src/mutation-node/mutation-subgraph.ts b/packages/mutator-framework/src/mutation-node/mutation-subgraph.ts deleted file mode 100644 index 4ada71da931..00000000000 --- a/packages/mutator-framework/src/mutation-node/mutation-subgraph.ts +++ /dev/null @@ -1,59 +0,0 @@ -import type { MemberType, Type } from "@typespec/compiler"; -import type { MutationEngine } from "../mutation/mutation-engine.js"; -import { mutationNodeFor, type MutationNodeForType } from "./factory.js"; -import type { MutationNode } from "./mutation-node.js"; - -/** - * A subgraph of mutation nodes such that there is one node per type in the graph. - */ -export class MutationSubgraph { - #seenNodes = new Map>(); - #seenReferenceNodes = new Map>(); - - engine: MutationEngine; - - constructor(engine: MutationEngine) { - this.engine = engine; - } - - getNode(type: T, memberReferences: MemberType[] = []): MutationNodeForType { - if (memberReferences.length > 0) { - return this.getReferenceNode(memberReferences[0]!) as any; - } - - if (this.#seenNodes.has(type)) { - return this.#seenNodes.get(type)! as MutationNodeForType; - } - - const node = mutationNodeFor(this, type); - this.#seenNodes.set(type, node); - node.traverse(); - - return node; - } - - getReferenceNode(memberType: MemberType): MutationNode { - if (this.#seenReferenceNodes.has(memberType)) { - return this.#seenReferenceNodes.get(memberType)!; - } - - let referencedType: Type = memberType; - while (referencedType.kind === "ModelProperty" || referencedType.kind === "UnionVariant") { - referencedType = referencedType.type; - } - const node = mutationNodeFor(this, referencedType); - node.referenceType = memberType; - this.#seenReferenceNodes.set(memberType, node); - node.traverse(); - - return node; - } - - replaceNode(oldNode: MutationNode, newNode: MutationNode) { - this.#seenNodes.set(oldNode.sourceType, newNode); - } - - replaceReferenceNode(referenceType: MemberType, newNode: MutationNode) { - this.#seenReferenceNodes.set(referenceType, newNode); - } -} diff --git a/packages/mutator-framework/src/mutation-node/operation.ts b/packages/mutator-framework/src/mutation-node/operation.ts index ad60773efaa..ef6b5a2272f 100644 --- a/packages/mutator-framework/src/mutation-node/operation.ts +++ b/packages/mutator-framework/src/mutation-node/operation.ts @@ -1,22 +1,21 @@ -import type { Model, Operation, Type } from "@typespec/compiler"; -import { MutationEdge } from "./mutation-edge.js"; +import type { Interface, Model, Operation, Type } from "@typespec/compiler"; +import { HalfEdge } from "./mutation-edge.js"; import { MutationNode } from "./mutation-node.js"; +export interface OperationConnectOptions { + /** Mutation key for the parameters node. Defaults to this node's key. */ + parameters?: string; + /** Mutation key for the return type node. Defaults to this node's key. */ + returnType?: string; +} + export class OperationMutationNode extends MutationNode { readonly kind = "Operation"; - traverse() { - const parameterNode = this.subgraph.getNode(this.sourceType.parameters); - this.connectParameters(parameterNode); - - const returnTypeNode = this.subgraph.getNode(this.sourceType.returnType); - this.connectReturnType(returnTypeNode); - } - - connectParameters(baseNode: MutationNode) { - MutationEdge.create(this, baseNode, { - onTailMutation: () => { - this.mutatedType!.parameters = baseNode.mutatedType; + startParametersEdge() { + return new HalfEdge(this, { + onTailMutation: ({ tail }) => { + this.mutatedType!.parameters = tail.mutatedType; }, onTailDeletion: () => { this.mutatedType.parameters = this.$.model.create({ @@ -24,26 +23,59 @@ export class OperationMutationNode extends MutationNode { properties: {}, }); }, - onTailReplaced: (newTail) => { + onTailReplaced: ({ newTail, head, reconnect }) => { if (newTail.mutatedType.kind !== "Model") { throw new Error("Cannot replace parameters with non-model type"); } - this.mutatedType.parameters = newTail.mutatedType; + head.mutatedType.parameters = newTail.mutatedType; + if (reconnect) { + head.connectParameters(newTail as MutationNode); + } }, }); } - connectReturnType(typeNode: MutationNode) { - MutationEdge.create(this, typeNode, { - onTailMutation: () => { - this.mutatedType!.returnType = typeNode.mutatedType; + connectParameters(baseNode: MutationNode) { + this.startParametersEdge().setTail(baseNode); + } + + startReturnTypeEdge() { + return new HalfEdge(this, { + onTailMutation: ({ tail }) => { + this.mutatedType!.returnType = tail.mutatedType; }, onTailDeletion: () => { this.mutatedType.returnType = this.$.intrinsic.void; }, - onTailReplaced: (newTail) => { - this.mutatedType.returnType = newTail.mutatedType; + onTailReplaced: ({ newTail, head, reconnect }) => { + head.mutatedType.returnType = newTail.mutatedType; + if (reconnect) { + head.connectReturnType(newTail); + } + }, + }); + } + + connectReturnType(typeNode: MutationNode) { + this.startReturnTypeEdge().setTail(typeNode); + } + + startInterfaceEdge() { + return new HalfEdge(this, { + onTailMutation: ({ tail }) => { + this.mutate(); + this.mutatedType.interface = tail.mutatedType; + }, + onTailDeletion: () => { + this.delete(); + }, + onTailReplaced: ({ head }) => { + head.delete(); }, }); } + + connectInterface(interfaceNode: MutationNode) { + this.startInterfaceEdge().setTail(interfaceNode); + } } diff --git a/packages/mutator-framework/src/mutation-node/scalar.test.ts b/packages/mutator-framework/src/mutation-node/scalar.test.ts index 40d600b00f5..0d02ab8e57a 100644 --- a/packages/mutator-framework/src/mutation-node/scalar.test.ts +++ b/packages/mutator-framework/src/mutation-node/scalar.test.ts @@ -1,20 +1,22 @@ -import { t, type TesterInstance } from "@typespec/compiler/testing"; +import { expectTypeEquals, t, type TesterInstance } from "@typespec/compiler/testing"; import { $ } from "@typespec/compiler/typekit"; import { beforeEach, expect, it } from "vitest"; import { Tester } from "../../test/test-host.js"; -import { getSubgraph } from "../../test/utils.js"; +import { getEngine } from "../../test/utils.js"; let runner: TesterInstance; beforeEach(async () => { runner = await Tester.createInstance(); }); + it("handles mutation of base scalars", async () => { const { program, Base, Derived } = await runner.compile(t.code` scalar ${t.scalar("Base")}; scalar ${t.scalar("Derived")} extends Base; `); - const subgraph = getSubgraph(program); - const baseNode = subgraph.getNode(Base); - const derivedNode = subgraph.getNode(Derived); + const engine = getEngine(program); + const baseNode = engine.getMutationNode(Base); + const derivedNode = engine.getMutationNode(Derived); + derivedNode.connectBaseScalar(baseNode); baseNode.mutate(); expect(baseNode.isMutated).toBe(true); @@ -27,18 +29,16 @@ it("handles replacement of scalars", async () => { scalar ${t.scalar("Base")}; scalar ${t.scalar("Derived")} extends Base; `); - const subgraph = getSubgraph(program); - const baseNode = subgraph.getNode(Base); - const derivedNode = subgraph.getNode(Derived); + const engine = getEngine(program); + const baseNode = engine.getMutationNode(Base); + const derivedNode = engine.getMutationNode(Derived); + derivedNode.connectBaseScalar(baseNode); const replacedNode = baseNode.replace($(program).builtin.string); expect(replacedNode.isMutated).toBe(true); expect(baseNode.isReplaced).toBe(true); - // subgraph is updated - expect(replacedNode === subgraph.getNode(Base)).toBe(true); - // derived node is updated expect(derivedNode.isMutated).toBe(true); - expect(derivedNode.mutatedType.baseScalar === replacedNode.sourceType).toBe(true); + expectTypeEquals(derivedNode.mutatedType.baseScalar!, replacedNode.sourceType); }); diff --git a/packages/mutator-framework/src/mutation-node/scalar.ts b/packages/mutator-framework/src/mutation-node/scalar.ts index bc30e41779d..3469b4a3e86 100644 --- a/packages/mutator-framework/src/mutation-node/scalar.ts +++ b/packages/mutator-framework/src/mutation-node/scalar.ts @@ -1,32 +1,39 @@ import type { Scalar } from "@typespec/compiler"; -import { MutationEdge } from "./mutation-edge.js"; +import { HalfEdge } from "./mutation-edge.js"; import { MutationNode } from "./mutation-node.js"; +export interface ScalarConnectOptions { + /** Mutation key for the base scalar node. Defaults to this node's key. */ + baseScalar?: string; +} + export class ScalarMutationNode extends MutationNode { readonly kind = "Scalar"; - traverse() { - if (this.sourceType.baseScalar) { - const baseScalarNode = this.subgraph.getNode(this.sourceType.baseScalar); - this.connectBaseScalar(baseScalarNode); - } - } - - connectBaseScalar(baseScalar: MutationNode) { - MutationEdge.create(this, baseScalar, { - onTailReplaced: (newTail) => { - if (!this.$.scalar.is(newTail.mutatedType)) { + startBaseScalarEdge() { + return new HalfEdge(this, { + onTailReplaced: ({ newTail, head, reconnect }) => { + if (!head.$.scalar.is(newTail.mutatedType)) { throw new Error("Cannot replace base scalar with non-scalar type"); } - - this.mutatedType.baseScalar = newTail.mutatedType; + head.mutate(); + head.mutatedType.baseScalar = newTail.mutatedType; + if (reconnect) { + head.connectBaseScalar(newTail as MutationNode); + } }, - onTailMutation: () => { - this.mutatedType.baseScalar = baseScalar.mutatedType; + onTailMutation: ({ tail }) => { + this.mutate(); + this.mutatedType.baseScalar = tail.mutatedType; }, onTailDeletion: () => { + this.mutate(); this.mutatedType.baseScalar = undefined; }, }); } + + connectBaseScalar(baseScalar: MutationNode) { + this.startBaseScalarEdge().setTail(baseScalar); + } } diff --git a/packages/mutator-framework/src/mutation-node/tracer.ts b/packages/mutator-framework/src/mutation-node/tracer.ts new file mode 100644 index 00000000000..79223b971b5 --- /dev/null +++ b/packages/mutator-framework/src/mutation-node/tracer.ts @@ -0,0 +1,18 @@ +import type { MutationEdge } from "./mutation-edge.js"; +import type { MutationNode } from "./mutation-node.js"; + +/** + * Useful tracing utilities to help debug mutation graphs. + */ +const shouldTrace = false; +export function traceNode(node: MutationNode, message: string = ""): void { + if (!shouldTrace) return; + // eslint-disable-next-line no-console + console.log(`${node}\n ${message}`); +} + +export function traceEdge(edge: MutationEdge, message: string = ""): void { + if (!shouldTrace) return; + // eslint-disable-next-line no-console + console.log(`${edge}\n ${message}`); +} diff --git a/packages/mutator-framework/src/mutation-node/tuple.test.ts b/packages/mutator-framework/src/mutation-node/tuple.test.ts index eec38073dfc..0b1f411f57c 100644 --- a/packages/mutator-framework/src/mutation-node/tuple.test.ts +++ b/packages/mutator-framework/src/mutation-node/tuple.test.ts @@ -3,7 +3,7 @@ import { t, type TesterInstance } from "@typespec/compiler/testing"; import { $ } from "@typespec/compiler/typekit"; import { beforeEach, expect, it } from "vitest"; import { Tester } from "../../test/test-host.js"; -import { getSubgraph } from "../../test/utils.js"; +import { getEngine } from "../../test/utils.js"; let runner: TesterInstance; beforeEach(async () => { runner = await Tester.createInstance(); @@ -17,10 +17,15 @@ it("handles mutation of element types", async () => { model ${t.model("Bar")} {} `); - const subgraph = getSubgraph(program); - const fooNode = subgraph.getNode(Foo); - const propNode = subgraph.getNode(prop); - const barNode = subgraph.getNode(Bar); + const engine = getEngine(program); + const fooNode = engine.getMutationNode(Foo); + const propNode = engine.getMutationNode(prop); + const barNode = engine.getMutationNode(Bar); + fooNode.connectProperty(propNode); + const tupleType = prop.type as Tuple; + const tupleNode = engine.getMutationNode(tupleType); + propNode.connectType(tupleNode); + tupleNode.connectElement(barNode, 0); barNode.mutate(); expect(barNode.isMutated).toBe(true); expect(propNode.isMutated).toBe(true); diff --git a/packages/mutator-framework/src/mutation-node/tuple.ts b/packages/mutator-framework/src/mutation-node/tuple.ts index de191b15267..a3a288b3051 100644 --- a/packages/mutator-framework/src/mutation-node/tuple.ts +++ b/packages/mutator-framework/src/mutation-node/tuple.ts @@ -1,35 +1,42 @@ import type { Tuple, Type } from "@typespec/compiler"; -import { MutationEdge } from "./mutation-edge.js"; +import { HalfEdge } from "./mutation-edge.js"; import { MutationNode } from "./mutation-node.js"; +export interface TupleConnectOptions { + /** Mutation keys for element nodes, keyed by index. Defaults to this node's key for all. */ + elements?: string[]; +} + export class TupleMutationNode extends MutationNode { readonly kind = "Tuple"; #indexMap: number[] = []; - traverse() { - for (let i = 0; i < this.sourceType.values.length; i++) { - const elemType = this.sourceType.values[i]; - const elemNode = this.subgraph.getNode(elemType); - this.#indexMap[i] = i; - this.connectElement(elemNode, i); - } - } - - connectElement(elemNode: MutationNode, index: number) { - MutationEdge.create(this, elemNode, { - onTailMutation: () => { - this.mutatedType.values[this.#indexMap[index]] = elemNode.mutatedType; + startElementEdge(index: number) { + this.#indexMap[index] = index; + return new HalfEdge(this, { + onTailMutation: ({ tail }) => { + this.mutate(); + this.mutatedType.values[this.#indexMap[index]] = tail.mutatedType; }, onTailDeletion: () => { + this.mutate(); const spliceIndex = this.#indexMap[index]; this.mutatedType.values.splice(spliceIndex, 1); for (let i = spliceIndex + 1; i < this.#indexMap.length; i++) { this.#indexMap[i]--; } }, - onTailReplaced: (newTail) => { - this.mutatedType.values[this.#indexMap[index]] = newTail.mutatedType; + onTailReplaced: ({ newTail, head, reconnect }) => { + head.mutate(); + head.mutatedType.values[this.#indexMap[index]] = newTail.mutatedType; + if (reconnect) { + head.connectElement(newTail, index); + } }, }); } + + connectElement(elemNode: MutationNode, index: number) { + this.startElementEdge(index).setTail(elemNode); + } } diff --git a/packages/mutator-framework/src/mutation-node/union-variant.test.ts b/packages/mutator-framework/src/mutation-node/union-variant.test.ts index a4658d7946f..3dfc0805119 100644 --- a/packages/mutator-framework/src/mutation-node/union-variant.test.ts +++ b/packages/mutator-framework/src/mutation-node/union-variant.test.ts @@ -2,7 +2,7 @@ import { t, type TesterInstance } from "@typespec/compiler/testing"; import { $ } from "@typespec/compiler/typekit"; import { beforeEach, expect, it } from "vitest"; import { Tester } from "../../test/test-host.js"; -import { getSubgraph } from "../../test/utils.js"; +import { getEngine } from "../../test/utils.js"; let runner: TesterInstance; beforeEach(async () => { runner = await Tester.createInstance(); @@ -16,13 +16,49 @@ it("handles mutation of variant types", async () => { } `); - const subgraph = getSubgraph(program); - const fooNode = subgraph.getNode(Foo); - const v1Node = subgraph.getNode(v1); - const stringNode = subgraph.getNode($(program).builtin.string); + const engine = getEngine(program); + const fooNode = engine.getMutationNode(Foo); + const v1Node = engine.getMutationNode(v1); + fooNode.connectVariant(v1Node); + const stringNode = engine.getMutationNode($(program).builtin.string); + v1Node.connectType(stringNode); stringNode.mutate(); expect(stringNode.isMutated).toBe(true); expect(v1Node.isMutated).toBe(true); expect(fooNode.isMutated).toBe(true); expect(v1Node.mutatedType.type === stringNode.mutatedType).toBeTruthy(); }); + +it("is deleted when its container union is deleted", async () => { + const { Foo, prop, program } = await runner.compile(t.code` + union ${t.union("Foo")} { + ${t.unionVariant("prop")}: string; + } + `); + const engine = getEngine(program); + const propNode = engine.getMutationNode(prop); + const fooNode = engine.getMutationNode(Foo); + fooNode.connectVariant(propNode); + const stringNode = engine.getMutationNode($(program).builtin.string); + propNode.connectType(stringNode); + + fooNode.delete(); + expect(propNode.isDeleted).toBe(true); +}); + +it("is deleted when its container union is replaced", async () => { + const { Foo, prop, program } = await runner.compile(t.code` + union ${t.union("Foo")} { + ${t.unionVariant("prop")}: string; + } + `); + const engine = getEngine(program); + const propNode = engine.getMutationNode(prop); + const fooNode = engine.getMutationNode(Foo); + fooNode.connectVariant(propNode); + const stringNode = engine.getMutationNode($(program).builtin.string); + propNode.connectType(stringNode); + + fooNode.replace($(program).builtin.string); + expect(propNode.isDeleted).toBe(true); +}); diff --git a/packages/mutator-framework/src/mutation-node/union-variant.ts b/packages/mutator-framework/src/mutation-node/union-variant.ts index 6a848668c4d..5e6a2ae6867 100644 --- a/packages/mutator-framework/src/mutation-node/union-variant.ts +++ b/packages/mutator-framework/src/mutation-node/union-variant.ts @@ -1,26 +1,55 @@ -import type { Type, UnionVariant } from "@typespec/compiler"; -import { MutationEdge } from "./mutation-edge.js"; +import type { Type, Union, UnionVariant } from "@typespec/compiler"; +import { HalfEdge } from "./mutation-edge.js"; import { MutationNode } from "./mutation-node.js"; +export interface UnionVariantConnectOptions { + /** Mutation key for the variant's type node. Defaults to this node's key. */ + type?: string; +} + export class UnionVariantMutationNode extends MutationNode { readonly kind = "UnionVariant"; - traverse() { - const typeNode = this.subgraph.getNode(this.sourceType.type); - this.connectType(typeNode); + startTypeEdge() { + return new HalfEdge(this, { + onTailMutation: ({ tail }) => { + this.mutate(); + this.mutatedType.type = tail.mutatedType; + }, + onTailDeletion: () => { + this.mutate(); + this.mutatedType.type = this.$.intrinsic.any; + }, + onTailReplaced: ({ newTail, head, reconnect }) => { + head.mutate(); + head.mutatedType.type = newTail.mutatedType; + if (reconnect) { + head.connectType(newTail); + } + }, + }); } connectType(typeNode: MutationNode) { - MutationEdge.create(this, typeNode, { - onTailMutation: () => { - this.mutatedType.type = typeNode.mutatedType; + this.startTypeEdge().setTail(typeNode); + } + + startUnionEdge() { + return new HalfEdge(this, { + onTailMutation: ({ tail }) => { + this.mutate(); + this.mutatedType.union = tail.mutatedType; }, onTailDeletion: () => { - this.mutatedType.type = this.$.intrinsic.any; + this.delete(); }, - onTailReplaced: (newTail) => { - this.mutatedType.type = newTail.mutatedType; + onTailReplaced: ({ head }) => { + head.delete(); }, }); } + + connectUnion(unionNode: MutationNode) { + this.startUnionEdge().setTail(unionNode); + } } diff --git a/packages/mutator-framework/src/mutation-node/union.test.ts b/packages/mutator-framework/src/mutation-node/union.test.ts index ca6c07c4f73..77d4bc82311 100644 --- a/packages/mutator-framework/src/mutation-node/union.test.ts +++ b/packages/mutator-framework/src/mutation-node/union.test.ts @@ -1,7 +1,7 @@ import { t, type TesterInstance } from "@typespec/compiler/testing"; import { beforeEach, expect, it } from "vitest"; import { Tester } from "../../test/test-host.js"; -import { getSubgraph } from "../../test/utils.js"; +import { getEngine } from "../../test/utils.js"; let runner: TesterInstance; beforeEach(async () => { runner = await Tester.createInstance(); @@ -15,9 +15,10 @@ it("handles mutation of variants", async () => { } `); - const subgraph = getSubgraph(program); - const fooNode = subgraph.getNode(Foo); - const v1Node = subgraph.getNode(v1); + const engine = getEngine(program); + const fooNode = engine.getMutationNode(Foo); + const v1Node = engine.getMutationNode(v1); + fooNode.connectVariant(v1Node); v1Node.mutate((clone) => (clone.name = "v1Renamed")); expect(v1Node.isMutated).toBe(true); expect(fooNode.isMutated).toBe(true); diff --git a/packages/mutator-framework/src/mutation-node/union.ts b/packages/mutator-framework/src/mutation-node/union.ts index 1874e20eb4a..ba9e7bc952e 100644 --- a/packages/mutator-framework/src/mutation-node/union.ts +++ b/packages/mutator-framework/src/mutation-node/union.ts @@ -1,33 +1,39 @@ import type { Union, UnionVariant } from "@typespec/compiler"; -import { MutationEdge } from "./mutation-edge.js"; +import { HalfEdge } from "./mutation-edge.js"; import { MutationNode } from "./mutation-node.js"; export class UnionMutationNode extends MutationNode { readonly kind = "Union"; - traverse(): void { - for (const variant of this.sourceType.variants.values()) { - const variantNode = this.subgraph.getNode(variant); - this.connectVariant(variantNode, variant.name); - } - } - - connectVariant(variantNode: MutationNode, sourcePropName: string | symbol) { - MutationEdge.create(this, variantNode, { - onTailMutation: () => { - this.mutatedType.variants.delete(sourcePropName); - this.mutatedType.variants.set(variantNode.mutatedType.name, variantNode.mutatedType); + startVariantEdge() { + return new HalfEdge(this, { + onTailCreation: ({ tail }) => { + tail.connectUnion(this); + }, + onTailMutation: ({ tail }) => { + this.mutate(); + this.mutatedType.variants.delete(tail.sourceType.name); + this.mutatedType.variants.set(tail.mutatedType.name, tail.mutatedType); }, - onTailDeletion: () => { - this.mutatedType.variants.delete(sourcePropName); + onTailDeletion: ({ tail }) => { + this.mutate(); + this.mutatedType.variants.delete(tail.sourceType.name); }, - onTailReplaced: (newTail) => { + onTailReplaced: ({ oldTail, newTail, head, reconnect }) => { if (newTail.mutatedType.kind !== "UnionVariant") { throw new Error("Cannot replace union variant with non-union variant type"); } - this.mutatedType.variants.delete(sourcePropName); - this.mutatedType.variants.set(newTail.mutatedType.name, newTail.mutatedType); + head.mutate(); + head.mutatedType.variants.delete(oldTail.sourceType.name); + head.mutatedType.variants.set(newTail.mutatedType.name, newTail.mutatedType); + if (reconnect) { + head.connectVariant(newTail as MutationNode); + } }, }); } + + connectVariant(variantNode: MutationNode) { + this.startVariantEdge().setTail(variantNode); + } } diff --git a/packages/mutator-framework/src/mutation/enum-member.ts b/packages/mutator-framework/src/mutation/enum-member.ts index db2d9c1b172..0ef3d896599 100644 --- a/packages/mutator-framework/src/mutation/enum-member.ts +++ b/packages/mutator-framework/src/mutation/enum-member.ts @@ -1,6 +1,6 @@ import type { EnumMember, MemberType } from "@typespec/compiler"; import type { CustomMutationClasses, MutationEngine, MutationOptions } from "./mutation-engine.js"; -import { Mutation } from "./mutation.js"; +import { Mutation, type MutationInfo } from "./mutation.js"; export class EnumMemberMutation< TOptions extends MutationOptions, @@ -14,8 +14,9 @@ export class EnumMemberMutation< sourceType: EnumMember, referenceTypes: MemberType[] = [], options: TOptions, + info: MutationInfo, ) { - super(engine, sourceType, referenceTypes, options); + super(engine, sourceType, referenceTypes, options, info); } mutate() { diff --git a/packages/mutator-framework/src/mutation/enum.ts b/packages/mutator-framework/src/mutation/enum.ts index 560a4e5133e..d1cdc57430f 100644 --- a/packages/mutator-framework/src/mutation/enum.ts +++ b/packages/mutator-framework/src/mutation/enum.ts @@ -5,7 +5,7 @@ import type { MutationFor, MutationOptions, } from "./mutation-engine.js"; -import { Mutation } from "./mutation.js"; +import { Mutation, type MutationInfo } from "./mutation.js"; export class EnumMutation< TOptions extends MutationOptions, @@ -20,8 +20,9 @@ export class EnumMutation< sourceType: Enum, referenceTypes: MemberType[] = [], options: TOptions, + info: MutationInfo, ) { - super(engine, sourceType, referenceTypes, options); + super(engine, sourceType, referenceTypes, options, info); } protected mutateMembers() { diff --git a/packages/mutator-framework/src/mutation/interface.ts b/packages/mutator-framework/src/mutation/interface.ts index f4770ee7239..037c3fcacb0 100644 --- a/packages/mutator-framework/src/mutation/interface.ts +++ b/packages/mutator-framework/src/mutation/interface.ts @@ -3,11 +3,12 @@ import type { CustomMutationClasses, MutationEngine, MutationFor, + MutationHalfEdge, MutationOptions, } from "./mutation-engine.js"; -import { Mutation } from "./mutation.js"; +import { Mutation, type MutationInfo } from "./mutation.js"; -export class InterfaceMutation< +export abstract class InterfaceMutation< TOptions extends MutationOptions, TCustomMutations extends CustomMutationClasses, > extends Mutation { @@ -17,21 +18,27 @@ export class InterfaceMutation< constructor( engine: MutationEngine, sourceType: Interface, - referenceTypes: MemberType[] = [], + referenceTypes: MemberType[], options: TOptions, + info: MutationInfo, ) { - super(engine, sourceType, referenceTypes, options); + super(engine, sourceType, referenceTypes, options, info); } protected mutateOperations() { for (const op of this.sourceType.operations.values()) { this.operations.set( op.name, - this.engine.mutate(op, this.options) as MutationFor, + this.engine.mutate(op, this.options, this.startOperationEdge()) as MutationFor< + TCustomMutations, + "Operation" + >, ); } } + protected abstract startOperationEdge(): MutationHalfEdge; + mutate() { this.mutateOperations(); } diff --git a/packages/mutator-framework/src/mutation/intrinsic.ts b/packages/mutator-framework/src/mutation/intrinsic.ts index 726bbbf9153..a94e39d3ed9 100644 --- a/packages/mutator-framework/src/mutation/intrinsic.ts +++ b/packages/mutator-framework/src/mutation/intrinsic.ts @@ -1,6 +1,6 @@ import type { IntrinsicType, MemberType } from "@typespec/compiler"; import type { CustomMutationClasses, MutationEngine, MutationOptions } from "./mutation-engine.js"; -import { Mutation } from "./mutation.js"; +import { Mutation, type MutationInfo } from "./mutation.js"; export class IntrinsicMutation< TOptions extends MutationOptions, @@ -11,10 +11,11 @@ export class IntrinsicMutation< constructor( engine: TEngine, sourceType: IntrinsicType, - referenceTypes: MemberType[] = [], + referenceTypes: MemberType[], options: TOptions, + info: MutationInfo, ) { - super(engine, sourceType, referenceTypes, options); + super(engine, sourceType, referenceTypes, options, info); } mutate() { diff --git a/packages/mutator-framework/src/mutation/literal.ts b/packages/mutator-framework/src/mutation/literal.ts index 15cd3f53312..16b3ce45356 100644 --- a/packages/mutator-framework/src/mutation/literal.ts +++ b/packages/mutator-framework/src/mutation/literal.ts @@ -1,6 +1,6 @@ import type { BooleanLiteral, MemberType, NumericLiteral, StringLiteral } from "@typespec/compiler"; import type { CustomMutationClasses, MutationEngine, MutationOptions } from "./mutation-engine.js"; -import { Mutation } from "./mutation.js"; +import { Mutation, type MutationInfo } from "./mutation.js"; export class LiteralMutation< TOptions extends MutationOptions, @@ -17,10 +17,11 @@ export class LiteralMutation< constructor( engine: TEngine, sourceType: StringLiteral | NumericLiteral | BooleanLiteral, - referenceTypes: MemberType[] = [], + referenceTypes: MemberType[], options: TOptions, + info: MutationInfo, ) { - super(engine, sourceType, referenceTypes, options); + super(engine, sourceType, referenceTypes, options, info); } mutate() { diff --git a/packages/mutator-framework/src/mutation/model-property.ts b/packages/mutator-framework/src/mutation/model-property.ts index 607c976f89a..6f781fd6da4 100644 --- a/packages/mutator-framework/src/mutation/model-property.ts +++ b/packages/mutator-framework/src/mutation/model-property.ts @@ -1,35 +1,28 @@ import type { ModelProperty, Type } from "@typespec/compiler"; -import type { MutationSubgraph } from "../mutation-node/mutation-subgraph.js"; import type { CustomMutationClasses, MutationEngine, MutationFor, + MutationHalfEdge, MutationOptions, } from "./mutation-engine.js"; import { Mutation } from "./mutation.js"; -export class ModelPropertyMutation< - TOptions extends MutationOptions, +export abstract class ModelPropertyMutation< TCustomMutations extends CustomMutationClasses, + TOptions extends MutationOptions, TEngine extends MutationEngine = MutationEngine, > extends Mutation { readonly kind = "ModelProperty"; type!: MutationFor; - mutate() { - this.type = this.engine.mutateReference(this.sourceType, this.options); + mutate(newOptions: MutationOptions = this.options) { + this.type = this.engine.mutateReference( + this.sourceType, + newOptions, + this.startTypeEdge(), + ) as MutationFor; } - getReferenceMutationNode( - subgraph: MutationSubgraph = this.engine.getDefaultMutationSubgraph(this.options), - ) { - return subgraph.getReferenceNode(this.sourceType); - } - - replaceReferencedType(subgraph: MutationSubgraph, newType: Type) { - // First, update the mutation node - subgraph.getReferenceNode(this.sourceType).replace(newType); - // then return a new reference mutation for the new type - return this.engine.mutateReference(this.sourceType, newType, this.options); - } + protected abstract startTypeEdge(): MutationHalfEdge; } diff --git a/packages/mutator-framework/src/mutation/model.ts b/packages/mutator-framework/src/mutation/model.ts index 7cd7311b500..c9f3b0f79af 100644 --- a/packages/mutator-framework/src/mutation/model.ts +++ b/packages/mutator-framework/src/mutation/model.ts @@ -3,13 +3,14 @@ import type { CustomMutationClasses, MutationEngine, MutationFor, + MutationHalfEdge, MutationOptions, } from "./mutation-engine.js"; -import { Mutation } from "./mutation.js"; +import { Mutation, type MutationInfo } from "./mutation.js"; -export class ModelMutation< - TOptions extends MutationOptions, +export abstract class ModelMutation< TCustomMutations extends CustomMutationClasses, + TOptions extends MutationOptions, TEngine extends MutationEngine = MutationEngine, > extends Mutation { readonly kind = "Model"; @@ -23,36 +24,57 @@ export class ModelMutation< constructor( engine: TEngine, sourceType: Model, - referenceTypes: MemberType[] = [], + referenceTypes: MemberType[], options: TOptions, + info: MutationInfo, ) { - super(engine, sourceType, referenceTypes, options); + super(engine, sourceType, referenceTypes, options, info); } - protected mutateBaseModel() { + protected mutateBaseModel(newOptions: MutationOptions = this.options) { if (this.sourceType.baseModel) { - this.baseModel = this.engine.mutate(this.sourceType.baseModel, this.options); + this.baseModel = this.engine.mutate( + this.sourceType.baseModel, + newOptions, + this.startBaseEdge(), + ); } } - protected mutateProperties() { + protected mutateProperties(newOptions: MutationOptions = this.options) { for (const prop of this.sourceType.properties.values()) { - this.properties.set(prop.name, this.engine.mutate(prop, this.options)); + this.properties.set( + prop.name, + this.engine.mutate(prop, newOptions, this.startPropertyEdge()), + ); } } - protected mutateIndexer() { + protected mutateIndexer(newOptions: MutationOptions = this.options) { if (this.sourceType.indexer) { this.indexer = { - key: this.engine.mutate(this.sourceType.indexer.key, this.options), - value: this.engine.mutate(this.sourceType.indexer.value, this.options), + key: this.engine.mutate( + this.sourceType.indexer.key, + newOptions, + this.startIndexerKeyEdge(), + ), + value: this.engine.mutate( + this.sourceType.indexer.value, + newOptions, + this.startIndexerValueEdge(), + ), }; } } - mutate() { - this.mutateBaseModel(); - this.mutateProperties(); - this.mutateIndexer(); + protected abstract startBaseEdge(): MutationHalfEdge; + protected abstract startPropertyEdge(): MutationHalfEdge; + protected abstract startIndexerValueEdge(): MutationHalfEdge; + protected abstract startIndexerKeyEdge(): MutationHalfEdge; + + mutate(newOptions: MutationOptions = this.options) { + this.mutateBaseModel(newOptions); + this.mutateProperties(newOptions); + this.mutateIndexer(newOptions); } } diff --git a/packages/mutator-framework/src/mutation/mutation-engine.test.ts b/packages/mutator-framework/src/mutation/mutation-engine.test.ts deleted file mode 100644 index 5ae67499b40..00000000000 --- a/packages/mutator-framework/src/mutation/mutation-engine.test.ts +++ /dev/null @@ -1,271 +0,0 @@ -import type { Enum, Model } from "@typespec/compiler"; -import { t } from "@typespec/compiler/testing"; -import { $, type Typekit } from "@typespec/compiler/typekit"; -import { expect, it } from "vitest"; -import { Tester } from "../../test/test-host.js"; -import type { MutationSubgraph } from "../mutation-node/mutation-subgraph.js"; -import { EnumMemberMutation } from "./enum-member.js"; -import { EnumMutation } from "./enum.js"; -import { ModelPropertyMutation } from "./model-property.js"; -import { ModelMutation } from "./model.js"; -import { MutationEngine, MutationOptions } from "./mutation-engine.js"; -import { SimpleMutationEngine } from "./simple-mutation-engine.js"; - -class RenameMutationOptions extends MutationOptions { - prefix: string; - suffix: string; - - constructor(prefix: string, suffix: string) { - super(); - this.prefix = prefix; - this.suffix = suffix; - } - - cacheKey() { - return `${this.prefix}-${this.suffix}`; - } -} - -class RenameMutationEngine extends MutationEngine { - constructor($: Typekit) { - super($, { - Model: RenameModelMutation, - }); - this.registerSubgraph("prefix"); - this.registerSubgraph("suffix"); - } - - getPrefixSubgraph(options: RenameMutationOptions): MutationSubgraph { - return this.getMutationSubgraph(options, "prefix"); - } - - getSuffixSubgraph(options: RenameMutationOptions): MutationSubgraph { - return this.getMutationSubgraph(options, "suffix"); - } -} - -interface RenameMutationClasses { - Model: RenameModelMutation; -} - -class RenameModelMutation extends ModelMutation< - RenameMutationOptions, - RenameMutationClasses, - RenameMutationEngine -> { - get #prefixSubgraph() { - return this.engine.getPrefixSubgraph(this.options); - } - - get #suffixSubgraph() { - return this.engine.getSuffixSubgraph(this.options); - } - - get withPrefix() { - return this.getMutatedType(this.#prefixSubgraph); - } - - get withSuffix() { - return this.getMutatedType(this.#suffixSubgraph); - } - - mutate() { - if ("name" in this.sourceType && typeof this.sourceType.name === "string") { - this.mutateType( - this.#prefixSubgraph, - (m) => (m.name = `${this.options.prefix}${this.sourceType.name}`), - ); - this.mutateType( - this.#suffixSubgraph, - (m) => (m.name = `${this.sourceType.name}${this.options.suffix}`), - ); - } - - // mutate all connected types passing on the same options - super.mutate(); - } -} -it("creates mutations", async () => { - const runner = await Tester.createInstance(); - const { Foo, Bar, prop, program } = await runner.compile(t.code` - model ${t.model("Foo")} { - ${t.modelProperty("prop")}: Bar; - } - - model ${t.model("Bar")} { - prop: string; - } - `); - - const tk = $(program); - const engine = new RenameMutationEngine(tk); - const options = new RenameMutationOptions("Pre", "Suf"); - const fooMutation = engine.mutate(Foo, options); - - // can navigate the mutation result to get prefix and suffix names side-by-side - expect(fooMutation.properties.size).toBe(1); - - const barMutation = fooMutation.properties.get("prop")!.type as RenameModelMutation; - expect(barMutation.withPrefix.name).toBe("PreBar"); - - // Or you could get barMutation like: - const barMutation2 = engine.mutate(Bar, options); - - // but these are not the same mutation node because the mutation accessed via - // the property is a distinct from the one accessed from the scalar. - expect(barMutation === barMutation2).toBe(false); - expect(barMutation.referenceTypes.length).toEqual(1); - expect(barMutation.referenceTypes[0] === prop).toBe(true); - expect(barMutation2.referenceTypes.length).toEqual(0); - - // The graph is mutated - const prefixModel = fooMutation.withPrefix; - const suffixModel = fooMutation.withSuffix; - - expect(prefixModel.name).toBe("PreFoo"); - expect((prefixModel.properties.get("prop")!.type as Model).name).toBe("PreBar"); - expect(suffixModel.name).toBe("FooSuf"); - expect((suffixModel.properties.get("prop")!.type as Model).name).toBe("BarSuf"); -}); - -interface UnionifyMutations { - Model: UnionifyModel; - ModelProperty: UnionifyProperty; -} - -class UnionifyModel extends ModelMutation< - MutationOptions, - UnionifyMutations, - SimpleMutationEngine -> { - get unionified() { - return this.getMutatedType(); - } -} - -class UnionifyProperty extends ModelPropertyMutation< - MutationOptions, - UnionifyMutations, - SimpleMutationEngine -> { - get unionified() { - return this.getMutatedType(); - } - - mutate() { - if (!this.engine.$.union.is(this.sourceType.type)) { - // turn it into this union: - const newUnionType = this.engine.$.union.create({ - variants: [ - this.engine.$.unionVariant.create({ type: this.sourceType.type }), - this.engine.$.unionVariant.create({ - type: this.engine.$.builtin.string, - }), - ], - }); - - this.type = this.replaceReferencedType( - this.engine.getDefaultMutationSubgraph(this.options), - newUnionType, - ); - } else { - super.mutate(); - } - } -} - -it("mutates model properties into unions", async () => { - const runner = await Tester.createInstance(); - const { Foo, program } = await runner.compile(t.code` - model ${t.model("Foo")} { - ${t.modelProperty("prop")}: Bar; - } - - model ${t.model("Bar")} { - barProp: string; - } - `); - - const tk = $(program); - const engine = new SimpleMutationEngine(tk, { - ModelProperty: UnionifyProperty, - Model: UnionifyModel, - }); - - const fooMutation = engine.mutate(Foo); - const propMutation = fooMutation.properties.get("prop")!; - const typeMutation = propMutation.type as UnionifyModel; - expect(typeMutation.kind).toBe("Union"); - const propType = propMutation.unionified; - expect(tk.union.is(propType.type)).toBe(true); - - const mutatedFoo = fooMutation.unionified; - expect(tk.union.is(mutatedFoo.properties.get("prop")!.type)).toBe(true); -}); - -interface RenameEnumMutations { - Enum: RenameEnumMutation; - EnumMember: RenameEnumMemberMutation; -} - -class RenameEnumMutation extends EnumMutation< - RenameMutationOptions, - RenameEnumMutations, - MutationEngine -> { - get withPrefix() { - return this.getMutatedType(); - } - - mutate() { - this.mutateType((e) => (e.name = `${this.options.prefix}${this.sourceType.name}`)); - super.mutate(); - } -} - -class RenameEnumMemberMutation extends EnumMemberMutation< - RenameMutationOptions, - RenameEnumMutations, - MutationEngine -> { - get withPrefix() { - return this.getMutatedType(); - } - - mutate() { - this.mutateType((m) => (m.name = `${this.options.prefix}${this.sourceType.name}`)); - super.mutate(); - } -} - -it("mutates enums and enum members", async () => { - const runner = await Tester.createInstance(); - const { Status, program } = await runner.compile(t.code` - enum ${t.enum("Status")} { - Active, - Inactive, - } - `); - - const tk = $(program); - const engine = new SimpleMutationEngine(tk, { - Enum: RenameEnumMutation, - EnumMember: RenameEnumMemberMutation, - }); - - const options = new RenameMutationOptions("Pre", "Suf"); - const enumMutation = engine.mutate(Status, options) as RenameEnumMutation; - - // Verify the enum and its members are mutated - expect(enumMutation.withPrefix.name).toBe("PreStatus"); - - const activeMutation = enumMutation.members.get("Active") as RenameEnumMemberMutation; - expect(activeMutation.withPrefix.name).toBe("PreActive"); - - // Verify the mutated enum has the renamed members - const mutatedEnum = enumMutation.withPrefix as Enum; - expect(mutatedEnum.members.has("PreActive")).toBe(true); - expect(mutatedEnum.members.has("PreInactive")).toBe(true); - expect(mutatedEnum.members.has("Active")).toBe(false); - expect(mutatedEnum.members.has("Inactive")).toBe(false); -}); diff --git a/packages/mutator-framework/src/mutation/mutation-engine.ts b/packages/mutator-framework/src/mutation/mutation-engine.ts index 31442508748..e59aa83a770 100644 --- a/packages/mutator-framework/src/mutation/mutation-engine.ts +++ b/packages/mutator-framework/src/mutation/mutation-engine.ts @@ -1,7 +1,7 @@ import type { MemberType, Type } from "@typespec/compiler"; import type { Typekit } from "@typespec/compiler/typekit"; -import type { MutationNodeForType } from "../mutation-node/factory.js"; -import { MutationSubgraph } from "../mutation-node/mutation-subgraph.js"; +import { mutationNodeFor, type MutationNodeForType } from "../mutation-node/factory.js"; +import { MutationNode, type MutationNodeOptions } from "../mutation-node/mutation-node.js"; import { EnumMemberMutation } from "./enum-member.js"; import { EnumMutation } from "./enum.js"; import { InterfaceMutation } from "./interface.js"; @@ -11,6 +11,7 @@ import { ModelPropertyMutation } from "./model-property.js"; import { ModelMutation } from "./model.js"; import { Mutation } from "./mutation.js"; import { OperationMutation } from "./operation.js"; + import { ScalarMutation } from "./scalar.js"; import { UnionVariantMutation } from "./union-variant.js"; import { UnionMutation } from "./union.js"; @@ -21,9 +22,9 @@ export interface DefaultMutationClasses; Interface: InterfaceMutation; - Model: ModelMutation; + Model: ModelMutation; Scalar: ScalarMutation; - ModelProperty: ModelPropertyMutation; + ModelProperty: ModelPropertyMutation; Union: UnionMutation; UnionVariant: UnionVariantMutation; Enum: EnumMutation; @@ -50,22 +51,51 @@ export type InstancesFor any>> [K in keyof T]: InstanceType; }; -export class MutationEngine { - $: Typekit; +export interface InitialMutationContext< + TSourceType extends Type, + TCustomMutations extends CustomMutationClasses, + TOptions extends MutationOptions = MutationOptions, + TEngine extends MutationEngine = MutationEngine, +> { + engine: TEngine; + sourceType: TSourceType; + referenceTypes: MemberType[]; + options: TOptions; +} - // Map of Type -> (Map of options.cacheKey() -> Mutation) - #mutationCache = new Map>>(); +export interface CreateMutationContext { + mutationKey: string; +} - // Map of MemberType -> (Map of options.cacheKey() -> Mutation) - #referenceMutationCache = new Map>>(); +export interface MutationContext< + TSourceType extends Type, + TCustomMutations extends CustomMutationClasses, + TOptions extends MutationOptions = MutationOptions, + TEngine extends MutationEngine = MutationEngine, +> extends InitialMutationContext, + CreateMutationContext {} - #subgraphNames = new Set(); +export interface MutationTraits { + isSynthetic?: boolean; +} - // Map of subgraph names -> (Map of options.cacheKey() -> MutationSubgraph) - #subgraphs = new Map>(); +/** + * Orchestrates type mutations using custom and default mutation classes. + */ +export class MutationEngine { + /** TypeSpec type utilities. */ + $: Typekit; - #mutatorClasses: MutationRegistry; + // Map of Type -> (Map of options.cacheKey() -> Mutation) + #mutationCache = new Map>>(); + #seenMutationNodes = new WeakMap>>(); + #mutatorClasses: ConstructorsFor; + /** + * Creates a mutation engine with optional custom mutation classes. + * @param $ - TypeSpec type utilities + * @param mutatorClasses - Custom mutation class constructors + */ constructor($: Typekit, mutatorClasses: ConstructorsFor) { this.$ = $; this.#mutatorClasses = { @@ -85,170 +115,112 @@ export class MutationEngine { } as any; } - protected registerSubgraph(name: string) { - this.#subgraphNames.add(name); - } - - protected getMutationSubgraph(options: MutationOptions, name?: string) { - const optionsKey = options?.cacheKey() ?? "default"; - if (!this.#subgraphs.has(optionsKey)) { - this.#subgraphs.set(optionsKey, new Map()); - } - const subgraphsForOptions = this.#subgraphs.get(optionsKey)!; - - name = name ?? "default"; - if (!subgraphsForOptions.has(name)) { - subgraphsForOptions.set(name, new MutationSubgraph(this)); - } - - return subgraphsForOptions.get(name)!; - } - - getDefaultMutationSubgraph(options?: MutationOptions): MutationSubgraph { - throw new Error("This mutation engine does not provide a default mutation subgraph."); - } - /** - * Retrieve the mutated type from the default mutation subgraph for the given options. + * Gets or creates a mutation node for the given type and key. + * @param type - Source type + * @param mutationKey - Cache key for the node + * @returns Mutation node for the type */ - getMutatedType(options: MutationOptions, sourceType: T): T; - /** - * Retrieve the mutated type from a specific mutation subgraph. - */ - getMutatedType(subgraph: MutationSubgraph, sourceType: T): T; - /** - * Retrieve the mutated type from either the default subgraph with the given - * options or a specific subgraph. - */ - getMutatedType( - subgraphOrOptions: MutationOptions | MutationSubgraph, - sourceType: T, - ): T; - getMutatedType( - subgraphOrOptions: MutationOptions | MutationSubgraph, - sourceType: T, - ) { - if (subgraphOrOptions instanceof MutationOptions) { - return this.getMutationNode(subgraphOrOptions, sourceType).mutatedType; + getMutationNode( + type: T, + options?: MutationNodeOptions | string, + ): MutationNodeForType { + let keyMap = this.#seenMutationNodes.get(type); + const mutationKey = typeof options === "string" ? options : (options?.mutationKey ?? ""); + if (keyMap) { + const existingNode = keyMap.get(mutationKey); + if (existingNode) { + return existingNode as MutationNodeForType; + } + } else { + keyMap = new Map(); + this.#seenMutationNodes.set(type, keyMap); } - return this.getMutationNode(subgraphOrOptions, sourceType).mutatedType; + + const node = mutationNodeFor(this, type, options); + keyMap.set(mutationKey, node); + return node; } /** - * Get (and potentially create) the mutation node for the provided type in the default subgraph. + * Replaces one mutation node with another in the cache. + * @param oldNode - Node to remove + * @param newNode - Node to add */ - getMutationNode(options: MutationOptions, type: T): MutationNodeForType; - /** - * Get (and potentially create) the mutation node for the provided type in a specific subgraph. - */ - getMutationNode(subgraph: MutationSubgraph, type: T): MutationNodeForType; + replaceMutationNode(oldNode: MutationNode, newNode: MutationNode) { + const oldKeyMap = this.#seenMutationNodes.get(oldNode.sourceType); + if (oldKeyMap) { + oldKeyMap.delete(oldNode.mutationKey); + } - /** - * Get (and potentially create) the mutation node for the provided type in - * either the default subgraph with the given options or a specific subgraph. - */ - getMutationNode( - subgraphOrOptions: MutationOptions | MutationSubgraph, - type: T, - ): MutationNodeForType; - getMutationNode(subgraphOrOptions: MutationOptions | MutationSubgraph, type: T) { - let subgraph: MutationSubgraph; - if (subgraphOrOptions instanceof MutationOptions) { - subgraph = this.getDefaultMutationSubgraph(subgraphOrOptions); - } else { - subgraph = subgraphOrOptions; + let newKeyMap = this.#seenMutationNodes.get(newNode.sourceType); + if (!newKeyMap) { + newKeyMap = new Map(); + this.#seenMutationNodes.set(newNode.sourceType, newKeyMap); } - return subgraph.getNode(type); + newKeyMap.set(newNode.mutationKey, newNode); } - mutateType( - subgraphOrOptions: MutationOptions | MutationSubgraph, - type: T, - initializeMutation: (type: T) => void, + /** + * Replaces a reference with a new type and mutates it. + * @param reference - Original reference to replace + * @param newType - New type to use + * @param options - Mutation options + * @param halfEdge - Optional half edge for tracking + * @returns Mutation for the new type + */ + replaceAndMutateReference( + reference: MemberType, + newType: TType, + options: MutationOptions = new MutationOptions(), + halfEdge?: MutationHalfEdge, ) { - const subgraph = this.#getSubgraphFromOptions(subgraphOrOptions); - this.getMutationNode(subgraph, type).mutate(initializeMutation as (type: Type) => void); - } - - #getSubgraphFromOptions(subgraphOrOptions: MutationOptions | MutationSubgraph) { - if (subgraphOrOptions instanceof MutationOptions) { - return this.getDefaultMutationSubgraph(subgraphOrOptions); - } else { - return subgraphOrOptions; - } + const { references } = resolveReference(reference); + const mut = this.mutateWorker(newType, references, options, halfEdge, { + isSynthetic: true, + }); + return mut; } - mutate( + /** + * Internal worker that creates or retrieves mutations with caching. + */ + protected mutateWorker( type: TType, - options: MutationOptions = new MutationOptions(), + references: MemberType[], + options: MutationOptions, + halfEdge?: MutationHalfEdge, + traits?: MutationTraits, ): MutationFor { + // initialize cache if (!this.#mutationCache.has(type)) { this.#mutationCache.set(type, new Map>()); } const byType = this.#mutationCache.get(type)!; - const key = options.cacheKey(); - if (byType.has(key)) { - const existing = byType.get(key)! as any; - if (!existing.isMutated) { - existing.isMutated = true; - existing.mutate(); - } - return existing; - } - - this.#initializeSubgraphs(type, options); - const mutatorClass = this.#mutatorClasses[type.kind]; if (!mutatorClass) { throw new Error("No mutator registered for type kind: " + type.kind); } - // TS doesn't like this abstract class here, but it will be a derivative - // class in practice. - const mutation = new (mutatorClass as any)(this, type, [], options); - - byType.set(key, mutation); - mutation.isMutated = true; - mutation.mutate(); - return mutation; - } - - mutateReference( - memberType: TType, - referencedMutationNode: Type, - options: MutationOptions, - ): MutationFor; - mutateReference( - memberType: TType, - options: MutationOptions, - ): MutationFor; - mutateReference( - memberType: TType, - referencedMutationNodeOrOptions: Type | MutationOptions, - options?: MutationOptions, - ): MutationFor { - let referencedMutationNode: Type | undefined; - let finalOptions: MutationOptions; - if (referencedMutationNodeOrOptions instanceof MutationOptions) { - finalOptions = referencedMutationNodeOrOptions; - referencedMutationNode = undefined; - } else { - referencedMutationNode = referencedMutationNodeOrOptions as Type; - finalOptions = options!; - } - - if (!this.#referenceMutationCache.has(memberType)) { - this.#referenceMutationCache.set( - memberType, - new Map>(), - ); + const info = (mutatorClass as any).mutationInfo( + this, + type, + references, + options, + halfEdge, + traits, + ); + if (info instanceof Mutation) { + // Already a mutation, return it directly. + // Type change mutations break types badly, but hopefully in general things "just work"? + return info as any; } - const byType = this.#referenceMutationCache.get(memberType)!; - const key = finalOptions.cacheKey(); + const key = info.mutationKey; if (byType.has(key)) { const existing = byType.get(key)! as any; + halfEdge?.setTail(existing); if (!existing.isMutated) { existing.isMutated = true; existing.mutate(); @@ -256,39 +228,92 @@ export class MutationEngine { return existing; } - this.#initializeSubgraphs(memberType, finalOptions); - const sources: MemberType[] = []; - - let referencedType: Type = memberType; - while (referencedType.kind === "ModelProperty" || referencedType.kind === "UnionVariant") { - sources.push(referencedType); - referencedType = referencedType.type; - } - - const typeToMutate = referencedMutationNode ?? referencedType; - const mutatorClass = this.#mutatorClasses[typeToMutate.kind]; - if (!mutatorClass) { - throw new Error("No mutator registered for type kind: " + typeToMutate.kind); - } - - const mutation = new (mutatorClass as any)(this, typeToMutate, sources, finalOptions); - + // TS doesn't like this abstract class here, but it will be a derivative + // class in practice. + const mutation = new (mutatorClass as any)(this, type, [], options, info); byType.set(key, mutation); mutation.isMutated = true; + halfEdge?.setTail(mutation); mutation.mutate(); return mutation; } - #initializeSubgraphs(root: Type, options: MutationOptions) { - for (const name of this.#subgraphNames) { - const subgraph = this.getMutationSubgraph(options, name); - subgraph.getNode(root); - } + /** + * Mutates a type using registered mutation classes. + * @param type - Type to mutate + * @param options - Mutation options + * @param halfEdge - Optional half edge for linking mutations to parent mutations + * @returns Mutation for the type + */ + mutate( + type: TType, + options: MutationOptions = new MutationOptions(), + halfEdge?: MutationHalfEdge, + traits?: MutationTraits, + ): MutationFor { + return this.mutateWorker(type, [], options, halfEdge, traits); + } + + /** + * Mutates a type through a reference chain (e.g., ModelProperty or UnionVariant). + * @param reference - Reference to mutate + * @param options - Mutation options + * @param halfEdge - Optional half edge for tracking + * @returns Mutation for the referenced type + */ + mutateReference( + reference: MemberType, + options: MutationOptions = new MutationOptions(), + halfEdge?: MutationHalfEdge, + traits?: MutationTraits, + ): MutationFor { + const { referencedType, references } = resolveReference(reference); + + return this.mutateWorker(referencedType, references, options, halfEdge, traits) as any; + } +} + +function resolveReference(reference: MemberType) { + const references: MemberType[] = []; + let referencedType: Type = reference; + while (referencedType.kind === "ModelProperty" || referencedType.kind === "UnionVariant") { + references.push(referencedType); + referencedType = referencedType.type; } + return { + referencedType, + references, + }; } export class MutationOptions { - cacheKey(): string { + get mutationKey(): string { return ""; } } + +/** + * Half-edge used to link mutations together. This represents the head-end of a + * mutation. When the tail is created, it is set on the half-edge and allows the + * head mutation to connect its nodes to the tail mutation. + */ +export class MutationHalfEdge< + THead extends Mutation = any, + TTail extends Mutation = any, +> { + head: THead; + tail: TTail | undefined; + readonly kind: string; + #onTailCreation: (tail: TTail) => void; + + constructor(kind: string, head: THead, onTailCreation: (tail: TTail) => void) { + this.kind = kind; + this.head = head; + this.#onTailCreation = onTailCreation; + } + + setTail(tail: TTail) { + this.tail = tail; + this.#onTailCreation(tail); + } +} diff --git a/packages/mutator-framework/src/mutation/mutation.ts b/packages/mutator-framework/src/mutation/mutation.ts index 40b77243682..4d77c245ced 100644 --- a/packages/mutator-framework/src/mutation/mutation.ts +++ b/packages/mutator-framework/src/mutation/mutation.ts @@ -1,7 +1,16 @@ import type { MemberType, Type } from "@typespec/compiler"; -import type { MutationNodeForType } from "../mutation-node/factory.js"; -import type { MutationSubgraph } from "../mutation-node/mutation-subgraph.js"; -import type { CustomMutationClasses, MutationEngine, MutationOptions } from "./mutation-engine.js"; +import type { + CustomMutationClasses, + MutationEngine, + MutationHalfEdge, + MutationOptions, + MutationTraits, +} from "./mutation-engine.js"; + +export interface MutationInfo extends Record { + mutationKey: string; + isSynthetic?: boolean; +} export abstract class Mutation< TSourceType extends Type, @@ -13,78 +22,43 @@ export abstract class Mutation< static readonly subgraphNames: string[] = []; - engine: TEngine; + protected engine: TEngine; sourceType: TSourceType; - options: TOptions; + protected options: TOptions; isMutated: boolean = false; - referenceTypes: MemberType[]; + protected referenceTypes: MemberType[]; + protected mutationInfo: MutationInfo; constructor( engine: TEngine, sourceType: TSourceType, referenceTypes: MemberType[], options: TOptions, + info: MutationInfo, ) { this.engine = engine; this.sourceType = sourceType; this.options = options; this.referenceTypes = referenceTypes; + this.mutationInfo = info; } - abstract mutate(): void; - - /** - * Retrieve the mutated type for this mutation's default subgraph. - */ - protected getMutatedType(): TSourceType; - /** - * Retrieve the mutated type for the provided subgraph. - */ - protected getMutatedType(subgraph: MutationSubgraph): TSourceType; - protected getMutatedType(subgraphOrOptions?: MutationSubgraph | MutationOptions) { - return this.engine.getMutatedType(subgraphOrOptions ?? this.options, this.sourceType); - } - - /** - * Retrieve the mutation node for this mutation's default subgraph. - */ - protected getMutationNode(): MutationNodeForType; - /** - * Retrieve the mutation node for the provided subgraph. - */ - protected getMutationNode(subgraph: MutationSubgraph): MutationNodeForType; - /** - * Retrieve the mutation node for either the default subgraph with the given - * options or a specific subgraph. - */ - protected getMutationNode( - subgraphOrOptions: MutationSubgraph | MutationOptions, - ): MutationNodeForType; - protected getMutationNode(subgraphOrOptions?: MutationSubgraph | MutationOptions) { - return this.engine.getMutationNode(subgraphOrOptions ?? this.options, this.sourceType); + get mutationEngine(): TEngine { + return this.engine; } - /** - * Mutate this type in the default subgraph. - */ - protected mutateType(initializeMutation?: (type: TSourceType) => void): void; - /** - * Mutate this type in the given subgraph - */ - protected mutateType( - subgraph: MutationSubgraph, - initializeMutation?: (type: TSourceType) => void, - ): void; - - protected mutateType( - subgraphOrInit?: MutationSubgraph | ((type: TSourceType) => void), - initializeMutation?: (type: TSourceType) => void, - ) { - if (typeof subgraphOrInit === "function") { - initializeMutation = subgraphOrInit; - subgraphOrInit = undefined; - } - const node = this.getMutationNode(subgraphOrInit ?? this.options); - node.mutate(initializeMutation as (type: Type) => void); + static mutationInfo( + engine: MutationEngine, + sourceType: Type, + referenceTypes: MemberType[], + options: MutationOptions, + halfEdge?: MutationHalfEdge, + traits?: MutationTraits, + ): MutationInfo | Mutation { + return { + mutationKey: options.mutationKey, + isSynthetic: traits?.isSynthetic, + }; } + abstract mutate(): void; } diff --git a/packages/mutator-framework/src/mutation/operation.ts b/packages/mutator-framework/src/mutation/operation.ts index 06b102da4ca..9b19bb4b867 100644 --- a/packages/mutator-framework/src/mutation/operation.ts +++ b/packages/mutator-framework/src/mutation/operation.ts @@ -3,11 +3,12 @@ import type { CustomMutationClasses, MutationEngine, MutationFor, + MutationHalfEdge, MutationOptions, } from "./mutation-engine.js"; -import { Mutation } from "./mutation.js"; +import { Mutation, type MutationInfo } from "./mutation.js"; -export class OperationMutation< +export abstract class OperationMutation< TOptions extends MutationOptions, TCustomMutations extends CustomMutationClasses, TEngine extends MutationEngine = MutationEngine, @@ -19,20 +20,32 @@ export class OperationMutation< constructor( engine: TEngine, sourceType: Operation, - referenceTypes: MemberType[] = [], + referenceTypes: MemberType[], options: TOptions, + info: MutationInfo, ) { - super(engine, sourceType, referenceTypes, options); + super(engine, sourceType, referenceTypes, options, info); } protected mutateParameters() { - this.parameters = this.engine.mutate(this.sourceType.parameters, this.options); + this.parameters = this.engine.mutate( + this.sourceType.parameters, + this.options, + this.startParametersEdge(), + ); } protected mutateReturnType() { - this.returnType = this.engine.mutate(this.sourceType.returnType, this.options); + this.returnType = this.engine.mutate( + this.sourceType.returnType, + this.options, + this.startReturnTypeEdge(), + ); } + protected abstract startParametersEdge(): MutationHalfEdge; + protected abstract startReturnTypeEdge(): MutationHalfEdge; + mutate() { this.mutateParameters(); this.mutateReturnType(); diff --git a/packages/mutator-framework/src/mutation/scalar.ts b/packages/mutator-framework/src/mutation/scalar.ts index 01ec5c65499..b129a90be71 100644 --- a/packages/mutator-framework/src/mutation/scalar.ts +++ b/packages/mutator-framework/src/mutation/scalar.ts @@ -3,11 +3,12 @@ import type { CustomMutationClasses, MutationEngine, MutationFor, + MutationHalfEdge, MutationOptions, } from "./mutation-engine.js"; -import { Mutation } from "./mutation.js"; +import { Mutation, type MutationInfo } from "./mutation.js"; -export class ScalarMutation< +export abstract class ScalarMutation< TOptions extends MutationOptions, TCustomMutations extends CustomMutationClasses, TEngine extends MutationEngine = MutationEngine, @@ -18,18 +19,25 @@ export class ScalarMutation< constructor( engine: TEngine, sourceType: Scalar, - referenceTypes: MemberType[] = [], + referenceTypes: MemberType[], options: TOptions, + info: MutationInfo, ) { - super(engine, sourceType, referenceTypes, options); + super(engine, sourceType, referenceTypes, options, info); } protected mutateBaseScalar() { if (this.sourceType.baseScalar) { - this.baseScalar = this.engine.mutate(this.sourceType.baseScalar, this.options); + this.baseScalar = this.engine.mutate( + this.sourceType.baseScalar, + this.options, + this.startBaseScalarEdge(), + ); } } + protected abstract startBaseScalarEdge(): MutationHalfEdge; + mutate() { this.mutateBaseScalar(); } diff --git a/packages/mutator-framework/src/mutation/simple-mutation-engine.test.ts b/packages/mutator-framework/src/mutation/simple-mutation-engine.test.ts new file mode 100644 index 00000000000..46d40908f18 --- /dev/null +++ b/packages/mutator-framework/src/mutation/simple-mutation-engine.test.ts @@ -0,0 +1,330 @@ +import type { MemberType, Model, Union } from "@typespec/compiler"; +import { expectTypeEquals, t } from "@typespec/compiler/testing"; +import { $ } from "@typespec/compiler/typekit"; +import { expect, it } from "vitest"; +import { Tester } from "../../test/test-host.js"; +import type { MutationHalfEdge, MutationTraits } from "./mutation-engine.js"; +import type { MutationInfo } from "./mutation.js"; +import { + SimpleIntrinsicMutation, + SimpleModelMutation, + SimpleModelPropertyMutation, + SimpleMutationEngine, + SimpleMutationOptions, + SimpleScalarMutation, + SimpleUnionMutation, + type SimpleMutationOptionsInit, +} from "./simple-mutation-engine.js"; + +interface RenameMutationOptionsInit extends SimpleMutationOptionsInit { + suffix: string; +} + +class RenameMutationOptions extends SimpleMutationOptions { + suffix: string; + + constructor(options: RenameMutationOptionsInit) { + super(options); + this.suffix = options.suffix; + } + + get mutationKey() { + return `${this.suffix}`; + } + + with(options: Partial) { + return new RenameMutationOptions({ + suffix: options.suffix ?? this.suffix, + }); + } +} + +class RenameModelMutation extends SimpleModelMutation { + mutate() { + if ("name" in this.sourceType && typeof this.sourceType.name === "string") { + this.mutationNode.mutate( + (type) => (type.name = `${this.sourceType.name}${this.options.suffix}`), + ); + } + super.mutate(); + } +} + +it("creates model and model property mutations", async () => { + const runner = await Tester.createInstance(); + const { Foo, program } = await runner.compile(t.code` + model ${t.model("Foo")} { + ${t.modelProperty("prop")}: Bar; + } + + model ${t.model("Bar")} { + prop: string; + } + `); + + const tk = $(program); + const engine = new SimpleMutationEngine<{ Model: RenameModelMutation }>(tk, { + Model: RenameModelMutation, + }); + + const options = new RenameMutationOptions({ suffix: "Suf" }); + const fooMutation = engine.mutate(Foo, options); + + expect(fooMutation.mutatedType.name).toBe("FooSuf"); + expect(fooMutation.properties.size).toBe(1); + + const propMutation = fooMutation.properties.get("prop")!; + expect(propMutation.mutatedType.model!.name).toBe("FooSuf"); + expect((propMutation.mutatedType.type as Model).name).toBe("BarSuf"); +}); + +it("attaches to existing mutations", async () => { + const runner = await Tester.createInstance(); + const { Foo, Bar, program } = await runner.compile(t.code` + model ${t.model("Foo")} { + ${t.modelProperty("prop")}: Bar; + } + + model ${t.model("Bar")} { + prop: string; + } + `); + + const tk = $(program); + const engine = new SimpleMutationEngine<{ Model: RenameModelMutation }>(tk, { + Model: RenameModelMutation, + }); + + const barMutation = engine.mutate(Bar, new RenameMutationOptions({ suffix: "X" })); + const fooMutation = engine.mutate(Foo, new RenameMutationOptions({ suffix: "X" })); + + expect(fooMutation.properties.get("prop")!.type === barMutation).toBe(true); + expectTypeEquals(fooMutation.properties.get("prop")!.mutatedType.type, barMutation.mutatedType); +}); + +class RenameModelBasedOnReferenceMutation extends SimpleModelMutation { + static mutationInfo( + engine: SimpleMutationEngine<{ Model: RenameModelBasedOnReferenceMutation }>, + sourceType: Model, + referenceTypes: MemberType[], + options: SimpleMutationOptions, + halfEdge?: MutationHalfEdge, + traits?: MutationTraits, + ): MutationInfo { + if (referenceTypes.length === 0) { + return { + mutationKey: options.mutationKey + "-no-ref", + hasReference: false, + isSynthetic: traits?.isSynthetic, + }; + } + return { + mutationKey: options.mutationKey + "-has-ref", + hasReference: true, + isSynthetic: traits?.isSynthetic, + }; + } + + mutate() { + if ( + "name" in this.sourceType && + typeof this.sourceType.name === "string" && + this.mutationInfo.hasReference + ) { + this.mutationNode.mutate((type) => (type.name = `${this.sourceType.name}Reference`)); + } + super.mutate(); + } +} + +it("plumbs mutation info", async () => { + const runner = await Tester.createInstance(); + const { Foo, program } = await runner.compile(t.code` + model ${t.model("Foo")} { + ${t.modelProperty("prop")}: Bar; + } + + model ${t.model("Bar")} { + barProp: string; + } + `); + + const tk = $(program); + const engine = new SimpleMutationEngine<{ Model: RenameModelBasedOnReferenceMutation }>(tk, { + Model: RenameModelBasedOnReferenceMutation, + }); + + const fooMutation = engine.mutate(Foo); + const propMutation = fooMutation.properties.get("prop")!; + const barRefMutation = propMutation.type as RenameModelBasedOnReferenceMutation; + const barRefPropMutation = barRefMutation.properties.get("barProp")!; + + expect(fooMutation.mutatedType.name).toBe("Foo"); + expect((propMutation.mutatedType.type as Model).name).toBe("BarReference"); + expect(barRefMutation.mutatedType.name).toBe("BarReference"); + expect(barRefPropMutation.mutatedType.name).toBe("barProp"); + expect(barRefPropMutation.mutatedType.model!.name).toBe("BarReference"); +}); + +interface UnionifyMutations { + ModelProperty: UnionifyProperty; +} + +class UnionifyProperty extends SimpleModelPropertyMutation { + mutate() { + if (!this.engine.$.union.is(this.sourceType.type)) { + // turn it into this union: + const newUnionType = this.engine.$.union.create({ + name: "DynamicUnion", + variants: [ + this.engine.$.unionVariant.create({ type: this.sourceType.type }), + this.engine.$.unionVariant.create({ + type: this.engine.$.builtin.string, + }), + ], + }); + + this.mutationNode.mutate((prop) => { + prop.type = newUnionType; + }); + + this.type = this.engine.replaceAndMutateReference( + this.sourceType, + newUnionType, + this.options, + this.startTypeEdge(), + ); + } else { + super.mutate(); + } + } +} + +it("allows replacing types", async () => { + const runner = await Tester.createInstance(); + const { Foo, program } = await runner.compile(t.code` + model ${t.model("Foo")} { + ${t.modelProperty("prop")}: int32; + } + `); + + const tk = $(program); + const engine = new SimpleMutationEngine(tk, { + ModelProperty: UnionifyProperty, + }); + + const fooMutation = engine.mutate(Foo); + const propMutation = fooMutation.properties.get("prop")!; + expect(propMutation.mutatedType.type.kind).toBe("Union"); + + const unionNode = propMutation.type as SimpleUnionMutation; + expect(unionNode.kind).toBe("Union"); + expect(unionNode.variants.size).toBe(2); + const variants = [...unionNode.variants.values()]; + + expect(variants[0].type.kind).toBe("Scalar"); + expectTypeEquals( + (variants[0].type as SimpleScalarMutation).mutatedType, + tk.builtin.int32, + ); + + expect(variants[1].type.kind).toBe("Scalar"); + expectTypeEquals( + (variants[1].type as SimpleScalarMutation).mutatedType, + tk.builtin.string, + ); +}); + +const nullableUnionCache = new WeakMap(); + +class NullableReferencedModelMutation extends SimpleModelMutation { + static mutationInfo( + engine: SimpleMutationEngine<{ Model: NullableReferencedModelMutation }>, + sourceType: Model, + referenceTypes: MemberType[], + options: SimpleMutationOptions, + halfEdge?: MutationHalfEdge, + traits?: MutationTraits, + ) { + if (referenceTypes.length > 0 && referenceTypes[0].kind === "ModelProperty") { + let nullableUnion = nullableUnionCache.get(sourceType); + if (!nullableUnion) { + nullableUnion = engine.$.union.create({ + name: `${sourceType.name ?? "Anonymous"}NullableUnion`, + variants: [ + engine.$.unionVariant.create({ name: "Value", type: sourceType }), + engine.$.unionVariant.create({ name: "Null", type: engine.$.intrinsic.null }), + ], + }); + nullableUnionCache.set(sourceType, nullableUnion); + } + + return engine.replaceAndMutateReference(referenceTypes[0], nullableUnion, options, halfEdge); + } + + return super.mutationInfo(engine, sourceType, referenceTypes, options, halfEdge, traits); + } +} + +it( + "substitutes referenced models with nullable unions", + async () => { + const runner = await Tester.createInstance(); + const { Foo, Bar, program } = await runner.compile(t.code` + model ${t.model("Bar")} { + value: string; + } + + model ${t.model("Foo")} { + prop: Bar; + } + `); + + const tk = $(program); + const engine = new SimpleMutationEngine<{ Model: NullableReferencedModelMutation }>(tk, { + Model: NullableReferencedModelMutation, + }); + + const barMutation = engine.mutate(Bar); + + expect(barMutation.kind).toBe("Model"); + expect(barMutation.mutatedType === Bar).toBe(true); + + const fooMutation = engine.mutate(Foo); + + expect(fooMutation.kind).toBe("Model"); + + const propMutation = fooMutation.properties.get("prop")!; + const nullableBarUnionMutation = + propMutation.type as SimpleUnionMutation; + + expect(nullableBarUnionMutation.kind).toBe("Union"); + const unionVariants = [...nullableBarUnionMutation.variants.values()]; + expect(unionVariants).toHaveLength(2); + + const modelVariant = unionVariants[0]; + expect(modelVariant.type.kind).toBe("Model"); + + const modelVariantMutation = modelVariant.type as SimpleModelMutation; + expect(modelVariantMutation.mutatedType === Bar).toBe(true); + + const nullVariant = unionVariants[1]; + expect(nullVariant.type.kind).toBe("Intrinsic"); + + const nullMutation = nullVariant.type as SimpleIntrinsicMutation; + expect(nullMutation.mutatedType === tk.intrinsic.null).toBe(true); + + const nullableBarUnderlyingType = propMutation.mutatedType.type as Union; + expect(nullableBarUnderlyingType.kind).toBe("Union"); + expect(nullableBarUnderlyingType.variants.size).toBe(2); + expect(nullableBarUnderlyingType === nullableBarUnionMutation.mutatedType).toBe(true); + + const [valueUnionVariant, nullUnionVariant] = [...nullableBarUnderlyingType.variants.values()]; + expect(valueUnionVariant.name).toBe("Value"); + expect(valueUnionVariant.type.kind).toBe("Model"); + expect((valueUnionVariant.type as Model).name).toBe("Bar"); + expect(nullUnionVariant.name).toBe("Null"); + expect(nullUnionVariant.type === tk.intrinsic.null).toBe(true); + }, + Infinity, +); diff --git a/packages/mutator-framework/src/mutation/simple-mutation-engine.ts b/packages/mutator-framework/src/mutation/simple-mutation-engine.ts index 9ed19bdc51e..9162171c7bb 100644 --- a/packages/mutator-framework/src/mutation/simple-mutation-engine.ts +++ b/packages/mutator-framework/src/mutation/simple-mutation-engine.ts @@ -1,21 +1,473 @@ +import type { + BooleanLiteral, + Interface, + IntrinsicType, + MemberType, + Model, + ModelProperty, + NumericLiteral, + Operation, + Scalar, + StringLiteral, + Type, + Union, + UnionVariant, +} from "@typespec/compiler"; import type { Typekit } from "@typespec/compiler/typekit"; -import type { MutationSubgraph } from "../mutation-node/mutation-subgraph.js"; +import { type MutationNodeForType } from "../mutation-node/factory.js"; +import type { InterfaceMutationNode } from "../mutation-node/interface.js"; +import type { IntrinsicMutationNode } from "../mutation-node/intrinsic.js"; +import type { LiteralMutationNode } from "../mutation-node/literal.js"; +import type { ModelPropertyMutationNode } from "../mutation-node/model-property.js"; +import type { ModelMutationNode } from "../mutation-node/model.js"; +import type { HalfEdge } from "../mutation-node/mutation-edge.js"; +import type { OperationMutationNode } from "../mutation-node/operation.js"; +import type { ScalarMutationNode } from "../mutation-node/scalar.js"; +import type { UnionVariantMutationNode } from "../mutation-node/union-variant.js"; +import type { UnionMutationNode } from "../mutation-node/union.js"; +import { InterfaceMutation } from "./interface.js"; +import { IntrinsicMutation } from "./intrinsic.js"; +import { LiteralMutation } from "./literal.js"; +import { ModelPropertyMutation } from "./model-property.js"; +import { ModelMutation } from "./model.js"; import { type ConstructorsFor, type CustomMutationClasses, MutationEngine, + MutationHalfEdge, MutationOptions, } from "./mutation-engine.js"; +import type { MutationInfo } from "./mutation.js"; +import { OperationMutation } from "./operation.js"; +import { ScalarMutation } from "./scalar.js"; +import { UnionVariantMutation } from "./union-variant.js"; +import { UnionMutation } from "./union.js"; +export interface SimpleMutations { + Operation: SimpleOperationMutation; + Interface: SimpleInterfaceMutation; + Model: SimpleModelMutation; + Scalar: SimpleScalarMutation; + ModelProperty: SimpleModelPropertyMutation; + Union: SimpleUnionMutation; + UnionVariant: SimpleUnionVariantMutation; + String: SimpleLiteralMutation; + Number: SimpleLiteralMutation; + Boolean: SimpleLiteralMutation; + Intrinsic: SimpleIntrinsicMutation; +} + +export type SimpleMutation = SimpleMutations[keyof SimpleMutations]; + +export interface SimpleMutationOptionsInit { + referenceEdge?: HalfEdge; +} + +export class SimpleMutationOptions extends MutationOptions { + constructor(init?: SimpleMutationOptionsInit) { + super(); + } +} + +/** + * The simple mutation engine and it's associated mutation classes allow for + * creating a mutated node for types in the type graph. + */ export class SimpleMutationEngine< TCustomMutations extends CustomMutationClasses, > extends MutationEngine { constructor($: Typekit, mutatorClasses: ConstructorsFor) { - super($, mutatorClasses); - this.registerSubgraph("subgraph"); + const defaultedMutatorClasses = { + Operation: mutatorClasses.Operation ?? SimpleOperationMutation, + Interface: mutatorClasses.Interface ?? SimpleInterfaceMutation, + Model: mutatorClasses.Model ?? SimpleModelMutation, + Scalar: mutatorClasses.Scalar ?? SimpleScalarMutation, + ModelProperty: mutatorClasses.ModelProperty ?? SimpleModelPropertyMutation, + Union: mutatorClasses.Union ?? SimpleUnionMutation, + UnionVariant: mutatorClasses.UnionVariant ?? SimpleUnionVariantMutation, + String: mutatorClasses.String ?? SimpleLiteralMutation, + Number: mutatorClasses.Number ?? SimpleLiteralMutation, + Boolean: mutatorClasses.Boolean ?? SimpleLiteralMutation, + Intrinsic: mutatorClasses.Intrinsic ?? SimpleIntrinsicMutation, + } as any; + super($, defaultedMutatorClasses); + } + + mutate( + type: TType, + options: MutationOptions = new SimpleMutationOptions(), + halfEdge?: MutationHalfEdge, + ) { + return super.mutate(type, options, halfEdge); + } + + mutateReference( + reference: MemberType, + options: MutationOptions = new SimpleMutationOptions(), + halfEdge?: MutationHalfEdge, + ) { + return super.mutateReference(reference, options, halfEdge); + } +} + +export interface SingleMutationNode { + mutationNode: MutationNodeForType; + mutatedType: T; +} + +export class SimpleModelMutation + extends ModelMutation< + SimpleMutations, + TOptions, + SimpleMutationEngine> + > + implements SingleMutationNode +{ + constructor( + engine: SimpleMutationEngine>, + sourceType: Model, + referenceTypes: MemberType[], + options: TOptions, + info: MutationInfo, + ) { + super(engine, sourceType, referenceTypes, options, info); + this.#mutationNode = this.engine.getMutationNode(this.sourceType, { + mutationKey: info.mutationKey, + isSynthetic: info.isSynthetic, + }); + } + + startBaseEdge() { + return this.#createHalfEdge("base", (tail) => + this.#mutationNode.connectBase(tail.mutationNode as ModelMutationNode), + ); + } + + startPropertyEdge() { + return this.#createHalfEdge("property", (tail) => + this.#mutationNode.connectProperty(tail.mutationNode as ModelPropertyMutationNode), + ); + } + + startIndexerKeyEdge() { + return this.#createHalfEdge("indexerKey", (tail) => + this.#mutationNode.connectIndexerKey(tail.mutationNode as ScalarMutationNode), + ); + } + + startIndexerValueEdge() { + return this.#createHalfEdge("indexerValue", (tail) => + this.#mutationNode.connectIndexerValue(tail.mutationNode as MutationNodeForType), + ); + } + + #createHalfEdge( + kind: string, + cb: (tail: SimpleMutation) => void, + ): MutationHalfEdge, SimpleMutation> { + return new MutationHalfEdge(kind, this, cb); + } + + #mutationNode: ModelMutationNode; + get mutationNode() { + return this.#mutationNode; + } + + get mutatedType() { + return this.#mutationNode.mutatedType; + } +} + +export class SimpleModelPropertyMutation + extends ModelPropertyMutation< + SimpleMutations, + TOptions, + SimpleMutationEngine> + > + implements SingleMutationNode +{ + constructor( + engine: SimpleMutationEngine>, + sourceType: ModelProperty, + referenceTypes: MemberType[], + options: TOptions, + info: MutationInfo, + ) { + super(engine, sourceType, referenceTypes, options, info); + this.#mutationNode = this.engine.getMutationNode(this.sourceType, { + mutationKey: info.mutationKey, + isSynthetic: info.isSynthetic, + }); + } + + startTypeEdge(): MutationHalfEdge { + return new MutationHalfEdge("type", this, (tail) => { + this.#mutationNode.connectType(tail.mutationNode as MutationNodeForType); + }); + } + + #mutationNode: ModelPropertyMutationNode; + get mutationNode() { + return this.#mutationNode; + } + + get mutatedType() { + return this.#mutationNode.mutatedType; + } +} + +export class SimpleUnionMutation + extends UnionMutation< + TOptions, + SimpleMutations, + SimpleMutationEngine> + > + implements SingleMutationNode +{ + constructor( + engine: SimpleMutationEngine>, + sourceType: Union, + referenceTypes: MemberType[], + options: TOptions, + info: MutationInfo, + ) { + super(engine, sourceType, referenceTypes, options, info); + this.#mutationNode = this.engine.getMutationNode(this.sourceType, { + mutationKey: info.mutationKey, + isSynthetic: info.isSynthetic, + }); + } + + protected startVariantEdge(): MutationHalfEdge { + return new MutationHalfEdge("variant", this, (tail) => { + this.#mutationNode.connectVariant(tail.mutationNode as UnionVariantMutationNode); + }); + } + + #mutationNode: UnionMutationNode; + get mutationNode() { + return this.#mutationNode; + } + + get mutatedType() { + return this.#mutationNode.mutatedType; + } +} + +export class SimpleUnionVariantMutation + extends UnionVariantMutation< + TOptions, + SimpleMutations, + SimpleMutationEngine> + > + implements SingleMutationNode +{ + constructor( + engine: SimpleMutationEngine>, + sourceType: UnionVariant, + referenceTypes: MemberType[], + options: TOptions, + info: MutationInfo, + ) { + super(engine, sourceType, referenceTypes, options, info); + this.#mutationNode = this.engine.getMutationNode(this.sourceType, { + mutationKey: info.mutationKey, + isSynthetic: info.isSynthetic, + }); + } + + protected startTypeEdge(): MutationHalfEdge { + return new MutationHalfEdge("type", this, (tail) => { + this.#mutationNode.connectType(tail.mutationNode as MutationNodeForType); + }); + } + + #mutationNode: UnionVariantMutationNode; + get mutationNode() { + return this.#mutationNode; + } + + get mutatedType() { + return this.#mutationNode.mutatedType; + } +} + +export class SimpleOperationMutation + extends OperationMutation< + TOptions, + SimpleMutations, + SimpleMutationEngine> + > + implements SingleMutationNode +{ + constructor( + engine: SimpleMutationEngine>, + sourceType: Operation, + referenceTypes: MemberType[], + options: TOptions, + info: MutationInfo, + ) { + super(engine, sourceType, referenceTypes, options, info); + this.#mutationNode = this.engine.getMutationNode(this.sourceType, { + mutationKey: info.mutationKey, + isSynthetic: info.isSynthetic, + }); + } + + protected startParametersEdge(): MutationHalfEdge { + return new MutationHalfEdge("parameters", this, (tail) => { + this.#mutationNode.connectParameters(tail.mutationNode as ModelMutationNode); + }); + } + + protected startReturnTypeEdge(): MutationHalfEdge { + return new MutationHalfEdge("returnType", this, (tail) => { + this.#mutationNode.connectReturnType(tail.mutationNode as MutationNodeForType); + }); + } + + #mutationNode: OperationMutationNode; + get mutationNode() { + return this.#mutationNode; + } + + get mutatedType() { + return this.#mutationNode.mutatedType; + } +} + +export class SimpleInterfaceMutation + extends InterfaceMutation> + implements SingleMutationNode +{ + constructor( + engine: SimpleMutationEngine>, + sourceType: Interface, + referenceTypes: MemberType[], + options: TOptions, + info: MutationInfo, + ) { + super(engine, sourceType, referenceTypes, options, info); + this.#mutationNode = this.engine.getMutationNode(this.sourceType, { + mutationKey: info.mutationKey, + isSynthetic: info.isSynthetic, + }); + } + + protected startOperationEdge(): MutationHalfEdge { + return new MutationHalfEdge("operation", this, (tail) => { + this.#mutationNode.connectOperation(tail.mutationNode as OperationMutationNode); + }); + } + + #mutationNode: InterfaceMutationNode; + get mutationNode() { + return this.#mutationNode; + } + + get mutatedType() { + return this.#mutationNode.mutatedType; + } +} + +export class SimpleScalarMutation + extends ScalarMutation< + TOptions, + SimpleMutations, + SimpleMutationEngine> + > + implements SingleMutationNode +{ + constructor( + engine: SimpleMutationEngine>, + sourceType: Scalar, + referenceTypes: MemberType[], + options: TOptions, + info: MutationInfo, + ) { + super(engine, sourceType, referenceTypes, options, info); + this.#mutationNode = this.engine.getMutationNode(this.sourceType, { + mutationKey: info.mutationKey, + isSynthetic: info.isSynthetic, + }); + } + + protected startBaseScalarEdge(): MutationHalfEdge { + return new MutationHalfEdge("base", this, (tail) => { + this.#mutationNode.connectBaseScalar(tail.mutationNode as ScalarMutationNode); + }); + } + + #mutationNode: ScalarMutationNode; + get mutationNode() { + return this.#mutationNode; + } + + get mutatedType() { + return this.#mutationNode.mutatedType; + } +} + +export class SimpleLiteralMutation + extends LiteralMutation< + TOptions, + SimpleMutations, + SimpleMutationEngine> + > + implements SingleMutationNode +{ + constructor( + engine: SimpleMutationEngine>, + sourceType: StringLiteral | NumericLiteral | BooleanLiteral, + referenceTypes: MemberType[], + options: TOptions, + info: MutationInfo, + ) { + super(engine, sourceType, referenceTypes, options, info); + this.#mutationNode = this.engine.getMutationNode(this.sourceType, { + mutationKey: info.mutationKey, + isSynthetic: info.isSynthetic, + }); + } + + #mutationNode: LiteralMutationNode; + get mutationNode() { + return this.#mutationNode; + } + + get mutatedType() { + return this.#mutationNode.mutatedType; + } +} + +export class SimpleIntrinsicMutation + extends IntrinsicMutation< + TOptions, + SimpleMutations, + SimpleMutationEngine> + > + implements SingleMutationNode +{ + constructor( + engine: SimpleMutationEngine>, + sourceType: IntrinsicType, + referenceTypes: MemberType[], + options: TOptions, + info: MutationInfo, + ) { + super(engine, sourceType, referenceTypes, options, info); + this.#mutationNode = this.engine.getMutationNode(this.sourceType, { + mutationKey: info.mutationKey, + isSynthetic: info.isSynthetic, + }); + } + + #mutationNode: IntrinsicMutationNode; + get mutationNode() { + return this.#mutationNode; } - getDefaultMutationSubgraph(options: MutationOptions): MutationSubgraph { - return super.getMutationSubgraph(options, "subgraph"); + get mutatedType() { + return this.#mutationNode.mutatedType; } } diff --git a/packages/mutator-framework/src/mutation/union-variant.ts b/packages/mutator-framework/src/mutation/union-variant.ts index e542d9aad14..98b21a780d2 100644 --- a/packages/mutator-framework/src/mutation/union-variant.ts +++ b/packages/mutator-framework/src/mutation/union-variant.ts @@ -3,11 +3,12 @@ import type { CustomMutationClasses, MutationEngine, MutationFor, + MutationHalfEdge, MutationOptions, } from "./mutation-engine.js"; -import { Mutation } from "./mutation.js"; +import { Mutation, type MutationInfo } from "./mutation.js"; -export class UnionVariantMutation< +export abstract class UnionVariantMutation< TOptions extends MutationOptions, TCustomMutations extends CustomMutationClasses, TEngine extends MutationEngine = MutationEngine, @@ -18,13 +19,16 @@ export class UnionVariantMutation< constructor( engine: TEngine, sourceType: UnionVariant, - referenceTypes: MemberType[] = [], + referenceTypes: MemberType[], options: TOptions, + info: MutationInfo, ) { - super(engine, sourceType, referenceTypes, options); + super(engine, sourceType, referenceTypes, options, info); } mutate(): void { - this.type = this.engine.mutate(this.sourceType.type, this.options); + this.type = this.engine.mutateReference(this.sourceType, this.options, this.startTypeEdge()); } + + protected abstract startTypeEdge(): MutationHalfEdge; } diff --git a/packages/mutator-framework/src/mutation/union.ts b/packages/mutator-framework/src/mutation/union.ts index 2a79d29cd5b..e7bc16c832f 100644 --- a/packages/mutator-framework/src/mutation/union.ts +++ b/packages/mutator-framework/src/mutation/union.ts @@ -3,11 +3,12 @@ import type { CustomMutationClasses, MutationEngine, MutationFor, + MutationHalfEdge, MutationOptions, } from "./mutation-engine.js"; -import { Mutation } from "./mutation.js"; +import { Mutation, type MutationInfo } from "./mutation.js"; -export class UnionMutation< +export abstract class UnionMutation< TOptions extends MutationOptions, TCustomMutations extends CustomMutationClasses, TEngine extends MutationEngine = MutationEngine, @@ -20,19 +21,23 @@ export class UnionMutation< sourceType: Union, referenceTypes: MemberType[] = [], options: TOptions, + info: MutationInfo, ) { - super(engine, sourceType, referenceTypes, options); + super(engine, sourceType, referenceTypes, options, info); } protected mutateVariants() { - this.variants = new Map( - [...this.sourceType.variants].map(([name, variant]) => [ - name, - this.engine.mutate(variant, this.options), - ]), - ); + const variants = [...this.sourceType.variants.values()]; + for (const variant of variants) { + this.variants.set( + variant.name, + this.engine.mutate(variant, this.options, this.startVariantEdge()), + ); + } } + protected abstract startVariantEdge(): MutationHalfEdge; + mutate() { this.mutateVariants(); } diff --git a/packages/mutator-framework/test/utils.ts b/packages/mutator-framework/test/utils.ts index 1feba3fd7ff..5e8f9780555 100644 --- a/packages/mutator-framework/test/utils.ts +++ b/packages/mutator-framework/test/utils.ts @@ -1,9 +1,8 @@ import type { Program } from "@typespec/compiler"; import { $ } from "@typespec/compiler/typekit"; -import { MutationEngine, MutationSubgraph } from "../src/index.js"; +import { MutationEngine } from "../src/index.js"; -export function getSubgraph(program: Program) { +export function getEngine(program: Program) { const tk = $(program); - const engine = new MutationEngine(tk, {}); - return new MutationSubgraph(engine); + return new MutationEngine(tk, {}); } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6670a369e4b..78d229980d2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -660,6 +660,9 @@ importers: '@typespec/compiler': specifier: workspace:^ version: link:../compiler + '@typespec/emitter-framework': + specifier: workspace:^ + version: link:../emitter-framework '@typespec/http': specifier: workspace:^ version: link:../http From 93a9c0e029ca35193fec9ef0bb07acc3826bd329 Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Tue, 16 Dec 2025 16:14:16 +0800 Subject: [PATCH 40/40] [Python] fix client default value for special headers (#9219) fix https://github.com/microsoft/typespec/issues/9217 add spector case https://github.com/Azure/typespec-azure/pull/3663 --- .chronus/changes/HEAD-2025-11-16-13-29-48.md | 7 +++++++ .../pygen/codegen/serializers/builder_serializer.py | 7 ++++++- 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 .chronus/changes/HEAD-2025-11-16-13-29-48.md diff --git a/.chronus/changes/HEAD-2025-11-16-13-29-48.md b/.chronus/changes/HEAD-2025-11-16-13-29-48.md new file mode 100644 index 00000000000..1d38a28a02a --- /dev/null +++ b/.chronus/changes/HEAD-2025-11-16-13-29-48.md @@ -0,0 +1,7 @@ +--- +changeKind: fix +packages: + - "@typespec/http-client-python" +--- + +fix client default value for special headers \ No newline at end of file diff --git a/packages/http-client-python/generator/pygen/codegen/serializers/builder_serializer.py b/packages/http-client-python/generator/pygen/codegen/serializers/builder_serializer.py index ef61ff347cc..d5db45a3294 100644 --- a/packages/http-client-python/generator/pygen/codegen/serializers/builder_serializer.py +++ b/packages/http-client-python/generator/pygen/codegen/serializers/builder_serializer.py @@ -403,7 +403,12 @@ def declare_non_inputtable_headers_queries( builder: RequestBuilderType, ) -> list[str]: def _get_value(param): - declaration = param.get_declaration() if param.constant else None + if param.constant: + declaration = param.get_declaration() + elif param.client_default_value_declaration is not None: + declaration = param.client_default_value_declaration + else: + declaration = None if param.location in [ParameterLocation.HEADER, ParameterLocation.QUERY]: kwarg_dict = "headers" if param.location == ParameterLocation.HEADER else "params" return f"_{kwarg_dict}.pop('{param.wire_name}', {declaration})"