From 01d73bb458165e86bc918927340c1fcf3610beab Mon Sep 17 00:00:00 2001 From: Ding Wang Date: Mon, 15 Apr 2024 13:05:59 -0700 Subject: [PATCH 1/9] resolveRef in autorest-canonical emitter --- .../typespec-autorest-canonical/README.md | 32 +++++ .../lib/autorest-canonical.tsp | 1 + .../lib/decorators.tsp | 12 ++ .../src/decorators.ts | 63 +++++++++ .../typespec-autorest-canonical/src/index.ts | 1 + .../typespec-autorest-canonical/src/lib.ts | 12 ++ .../src/openapi.ts | 44 ++++++- .../test/decorators.test.ts | 120 +++++++++++++++++- 8 files changed, 277 insertions(+), 8 deletions(-) create mode 100644 packages/typespec-autorest-canonical/lib/decorators.tsp create mode 100644 packages/typespec-autorest-canonical/src/decorators.ts diff --git a/packages/typespec-autorest-canonical/README.md b/packages/typespec-autorest-canonical/README.md index 08ceeaf0ce..967ab3fef2 100644 --- a/packages/typespec-autorest-canonical/README.md +++ b/packages/typespec-autorest-canonical/README.md @@ -58,6 +58,12 @@ Example: Multiple services Set the newline character for emitting files. +#### `arm-types-dir` + +**Type:** `string` + +Path to the common-types.json file folder. Default: '${project-root}/../../common-types/resource-management' + #### `omit-unreachable-types` **Type:** `boolean` @@ -70,3 +76,29 @@ Omit unreachable types. By default all types declared under the service namespac If the generated openapi types should have the `x-typespec-name` extension set with the name of the TypeSpec type that created it. This extension is meant for debugging and should not be depended on. + +## Decorators + +### Autorest + +- [`@useRef`](#@useref) + +#### `@useRef` + +`@useRef` - is used to replace the TypeSpec model type in emitter output with a pre-existing named OpenAPI schema such as Azure Resource Manager common types. + +`@useRef` can be specified on Models and ModelProperty. + +```typespec +@Autorest.useRef(jsonRef: valueof string) +``` + +##### Target + +`Model | ModelProperty` + +##### Parameters + +| Name | Type | Description | +| ------- | ---------------- | --------------------------------- | +| jsonRef | `valueof string` | path or Uri to an OpenAPI schema. | diff --git a/packages/typespec-autorest-canonical/lib/autorest-canonical.tsp b/packages/typespec-autorest-canonical/lib/autorest-canonical.tsp index 06847d5a6d..9ee8dde558 100644 --- a/packages/typespec-autorest-canonical/lib/autorest-canonical.tsp +++ b/packages/typespec-autorest-canonical/lib/autorest-canonical.tsp @@ -1 +1,2 @@ +import "./decorators.tsp"; import "../dist/src/index.js"; diff --git a/packages/typespec-autorest-canonical/lib/decorators.tsp b/packages/typespec-autorest-canonical/lib/decorators.tsp new file mode 100644 index 0000000000..8e70b996a1 --- /dev/null +++ b/packages/typespec-autorest-canonical/lib/decorators.tsp @@ -0,0 +1,12 @@ +using TypeSpec.Reflection; + +namespace AutorestCanonical; + +/** + * `@useRef` - is used to replace the TypeSpec model type in emitter output with a pre-existing named OpenAPI schema such as Azure Resource Manager common types. + * + * `@useRef` can be specified on Models and ModelProperty. + * + * @param jsonRef - path or Uri to an OpenAPI schema. + */ +extern dec useRef(entity: Model | ModelProperty, jsonRef: valueof string); diff --git a/packages/typespec-autorest-canonical/src/decorators.ts b/packages/typespec-autorest-canonical/src/decorators.ts new file mode 100644 index 0000000000..634f076905 --- /dev/null +++ b/packages/typespec-autorest-canonical/src/decorators.ts @@ -0,0 +1,63 @@ +import { DecoratorContext, Model, ModelProperty, Program, Service, Type } from "@typespec/compiler"; +import { createStateSymbol } from "./lib.js"; + +export const namespace = "AutorestCanonical"; + +/** + * Parameters that may be passed to a RefProducer function. Specific RefProducer + * functions may define additional parameters. + */ +export interface RefProducerParams { + service?: Service; + version?: string; +} + +/** + * A function that can produce a ref path at the time it is requested. + */ +export type RefProducer = ( + program: Program, + entity: Model | ModelProperty, + params: RefProducerParams +) => string | undefined; + +const refTargetsKey = createStateSymbol("autorestcanonical.ref"); +/** + * `@useRef` - is used to replace the TypeSpec model type in emitter output with a pre-existing named OpenAPI schema such as ARM common types. + * + * @param {string} param jsonRef - path or Uri to an OpenAPI schema. + * + * `@useRef` can be specified on Models and ModelProperty. + */ +export function $useRef(context: DecoratorContext, entity: Model | ModelProperty, jsonRef: string) { + context.program.stateMap(refTargetsKey).set(entity, jsonRef); +} + +/** + * Configures a "ref producer" for the given entity. A ref producer is a + * function that returns a ref path for the given entity, possibly altered by + * the options provided to the function (like the service and version). + * + * @param {function} param producer - path or Uri to an OpenAPI schema. + * + */ +export function setRefProducer( + program: Program, + entity: Model | ModelProperty, + refProducer: RefProducer +) { + program.stateMap(refTargetsKey).set(entity, refProducer); +} + +export function getRef( + program: Program, + entity: Type, + params?: RefProducerParams +): string | undefined { + const refOrProducer = program.stateMap(refTargetsKey).get(entity); + if (typeof refOrProducer === "function") { + return refOrProducer(program, entity, params ?? {}); + } else { + return refOrProducer; + } +} diff --git a/packages/typespec-autorest-canonical/src/index.ts b/packages/typespec-autorest-canonical/src/index.ts index 64231b619f..9088729ddd 100644 --- a/packages/typespec-autorest-canonical/src/index.ts +++ b/packages/typespec-autorest-canonical/src/index.ts @@ -1,2 +1,3 @@ +export * from "./decorators.js"; export { $lib, AutorestCanonicalEmitterOptions } from "./lib.js"; export * from "./openapi.js"; diff --git a/packages/typespec-autorest-canonical/src/lib.ts b/packages/typespec-autorest-canonical/src/lib.ts index f3aca79474..d1bc2d4610 100644 --- a/packages/typespec-autorest-canonical/src/lib.ts +++ b/packages/typespec-autorest-canonical/src/lib.ts @@ -47,6 +47,12 @@ export interface AutorestCanonicalEmitterOptions { * @default "never" */ "include-x-typespec-name"?: "inline-only" | "never"; + + /** + * Path to the common-types.json file folder. + * @default "${project-root}/../../common-types/resource-management" + */ + "arm-types-dir"?: string; } const EmitterOptionsSchema: JSONSchemaType = { @@ -74,6 +80,12 @@ const EmitterOptionsSchema: JSONSchemaType = { ].join("\n"), }, "azure-resource-provider-folder": { type: "string", nullable: true }, + "arm-types-dir": { + type: "string", + nullable: true, + description: + "Path to the common-types.json file folder. Default: '${project-root}/../../common-types/resource-management'", + }, "new-line": { type: "string", enum: ["crlf", "lf"], diff --git a/packages/typespec-autorest-canonical/src/openapi.ts b/packages/typespec-autorest-canonical/src/openapi.ts index 41ce9918fe..c052f7f310 100644 --- a/packages/typespec-autorest-canonical/src/openapi.ts +++ b/packages/typespec-autorest-canonical/src/openapi.ts @@ -41,6 +41,7 @@ import { compilerAssert, emitFile, getAllTags, + getDirectoryPath, getDiscriminator, getDoc, getEncode, @@ -57,6 +58,8 @@ import { getProjectedName, getProperty, getPropertyType, + getRelativePathFromDirectory, + getRootLength, getService, getSummary, getVisibility, @@ -145,6 +148,7 @@ import { Refable, } from "./types.js"; import { AutorestCanonicalEmitterContext, resolveOperationId } from "./utils.js"; +import { getRef } from "./decorators.js"; const defaultOptions = { "output-file": "{azure-resource-provider-folder}/{service-name}/{version}/openapi.json", @@ -158,16 +162,18 @@ enum UnsupportedVersioningDecorators { TypeChangedFrom = "typeChangedFrom", } -export const namespace = "AutorestCanonical"; export const canonicalVersion = "canonical"; export async function $onEmit(context: EmitContext) { const resolvedOptions = { ...defaultOptions, ...context.options }; const tcgcSdkContext = createSdkContext(context, "@azure-tools/typespec-autorest-canonical"); - const armTypesDir = interpolatePath("{project-root}/../../common-types/resource-management", { - "project-root": context.program.projectRoot, - "emitter-output-dir": context.emitterOutputDir, - }); + const armTypesDir = interpolatePath( + resolvedOptions["arm-types-dir"] ?? "{project-root}/../../common-types/resource-management", + { + "project-root": context.program.projectRoot, + "emitter-output-dir": context.emitterOutputDir, + } + ); const options: ResolvedAutorestCanonicalEmitterOptions = { outputFile: resolvedOptions["output-file"], outputDir: context.emitterOutputDir, @@ -827,7 +833,25 @@ function createOAPIEmitter( return header; } + function resolveRef(ref: string) { + const absoluteRef = interpolatePath(ref, { + "arm-types-dir": options.armTypesDir, + }); + + if (getRootLength(absoluteRef) === 0) { + return absoluteRef; // It is already relative. + } + return getRelativePathFromDirectory(getDirectoryPath(outputFile), absoluteRef, false); + } + function getSchemaOrRef(type: Type, visibility: Visibility): any { + const refUrl = getRef(program, type, { version: context.version, service: context.service }); + if (refUrl) { + return { + $ref: resolveRef(refUrl), + }; + } + if (type.kind === "Scalar" && program.checker.isStdType(type)) { return getSchemaForScalar(type); } @@ -915,6 +939,16 @@ function createOAPIEmitter( } } + const refUrl = getRef(program, property, { + version: context.version, + service: context.service, + }); + if (refUrl) { + return { + $ref: resolveRef(refUrl), + }; + } + const parameter = params.get(property); if (parameter) { return parameter; diff --git a/packages/typespec-autorest-canonical/test/decorators.test.ts b/packages/typespec-autorest-canonical/test/decorators.test.ts index 60221b3ebc..d5f0f05274 100644 --- a/packages/typespec-autorest-canonical/test/decorators.test.ts +++ b/packages/typespec-autorest-canonical/test/decorators.test.ts @@ -1,9 +1,11 @@ import { getAsEmbeddingVector } from "@azure-tools/typespec-azure-core"; -import { Model, Namespace, Scalar } from "@typespec/compiler"; -import { BasicTestRunner } from "@typespec/compiler/testing"; +import { Model, Namespace, Scalar, resolvePath } from "@typespec/compiler"; +import { BasicTestRunner, expectDiagnosticEmpty, expectDiagnostics, resolveVirtualPath } from "@typespec/compiler/testing"; import { deepStrictEqual, strictEqual } from "assert"; import { beforeEach, describe, it } from "vitest"; -import { createAutorestCanonicalTestRunner, openApiFor } from "./test-host.js"; +import { createAutorestCanonicalTestRunner, ignoreDiagnostics, ignoreUseStandardOps, openApiFor } from "./test-host.js"; +import { AutorestCanonicalTestLibrary } from "../src/testing/index.js"; +import { getRef } from "../src/decorators.js"; let runner: BasicTestRunner; @@ -52,3 +54,115 @@ describe("@operationId", () => { deepStrictEqual(openapi.paths["/"].get.operationId, "Pets_GET"); }); }); + +describe("@useRef", () => { + it("emit diagnostic if use on non model or property", async () => { + const diagnostics = await runner.diagnose(` + @useRef("foo") + op foo(): string; + `); + + expectDiagnostics(ignoreUseStandardOps(diagnostics), { + code: "decorator-wrong-target", + message: + "Cannot apply @useRef decorator to foo since it is not assignable to Model | ModelProperty", + }); + }); + + it("emit diagnostic if ref is not a string", async () => { + const diagnostics = await runner.diagnose(` + @useRef(123) + model Foo {} + `); + + expectDiagnostics(ignoreUseStandardOps(diagnostics), { + code: "invalid-argument", + message: "Argument '123' is not assignable to parameter of type 'valueof string'", + }); + }); + + it("emit diagnostic if ref is not passed", async () => { + const diagnostics = await runner.diagnose(` + @useRef + model Foo {} + `); + + expectDiagnostics(ignoreUseStandardOps(diagnostics), [ + { + code: "invalid-argument-count", + message: "Expected 1 arguments, but got 0.", + }, + ]); + }); + + it("set external reference", async () => { + const [{ Foo }, diagnostics] = await runner.compileAndDiagnose(` + @test @useRef("../common.json#/definitions/Foo") + model Foo {} + `); + + expectDiagnosticEmpty( + ignoreDiagnostics(diagnostics, [ + "@azure-tools/typespec-azure-core/use-standard-operations", + "@typespec/http/no-service-found", + ]) + ); + + strictEqual(getRef(runner.program, Foo), "../common.json#/definitions/Foo"); + }); + + describe("interpolate arm-types-dir", () => { + async function testArmTypesDir(options?: any) { + const code = ` + @test @useRef("{arm-types-dir}/common.json#/definitions/Foo") + model Foo {} + + model Bar { + foo: Foo; + } + `; + const runner = await createAutorestCanonicalTestRunner(); + const outputDir = resolveVirtualPath(`specification/org/service/output`); + const diagnostics = await runner.diagnose(code, { + noEmit: false, + config: resolveVirtualPath("specification/org/service/tspconfig.json"), + emitters: { + [AutorestCanonicalTestLibrary.name]: { + ...options, + "emitter-output-dir": outputDir, + }, + }, + }); + + expectDiagnosticEmpty( + ignoreDiagnostics(diagnostics, [ + "@azure-tools/typespec-azure-core/use-standard-operations", + "@typespec/http/no-service-found", + ]) + ); + + const outPath = resolvePath(outputDir, "canonical/openapi.json"); + const openAPI = JSON.parse(runner.fs.get(outPath)!); + return openAPI.definitions.Bar.properties.foo.$ref; + } + // project-root resolve to "" in test + it("To ${project-root}../../ by default", async () => { + const ref = await testArmTypesDir(); + strictEqual(ref, "../../../../common-types/resource-management/common.json#/definitions/Foo"); + }); + + it("configure a new absolute value", async () => { + const ref = await testArmTypesDir({ + "arm-types-dir": "{project-root}/../other/path", + }); + strictEqual(ref, "../../../other/path/common.json#/definitions/Foo"); + }); + + it("keeps relative value as it is", async () => { + const ref = await testArmTypesDir({ + "arm-types-dir": "../other/path", + }); + strictEqual(ref, "../other/path/common.json#/definitions/Foo"); + }); + }); +}); From c3ed2f6268890e723f5adaebfc1e72745f1d8de6 Mon Sep 17 00:00:00 2001 From: Ding Date: Wed, 17 Apr 2024 11:13:44 -0700 Subject: [PATCH 2/9] remove decorator --- ...date-resolveRef-2024-2024-4-17-11-10-36.md | 8 ++ .../typespec-autorest-canonical/README.md | 26 ---- .../lib/autorest-canonical.tsp | 1 - .../lib/decorators.tsp | 12 -- .../src/decorators.ts | 28 +--- .../test/decorators.test.ts | 120 +----------------- 6 files changed, 12 insertions(+), 183 deletions(-) create mode 100644 .chronus/changes/update-resolveRef-2024-2024-4-17-11-10-36.md delete mode 100644 packages/typespec-autorest-canonical/lib/decorators.tsp diff --git a/.chronus/changes/update-resolveRef-2024-2024-4-17-11-10-36.md b/.chronus/changes/update-resolveRef-2024-2024-4-17-11-10-36.md new file mode 100644 index 0000000000..b9d95173a0 --- /dev/null +++ b/.chronus/changes/update-resolveRef-2024-2024-4-17-11-10-36.md @@ -0,0 +1,8 @@ +--- +# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking +changeKind: fix +packages: + - "@azure-tools/typespec-autorest-canonical" +--- + +Add resolveRef logic for the typespec-autorest-canonical emitter diff --git a/packages/typespec-autorest-canonical/README.md b/packages/typespec-autorest-canonical/README.md index 967ab3fef2..7e662b0d8e 100644 --- a/packages/typespec-autorest-canonical/README.md +++ b/packages/typespec-autorest-canonical/README.md @@ -76,29 +76,3 @@ Omit unreachable types. By default all types declared under the service namespac If the generated openapi types should have the `x-typespec-name` extension set with the name of the TypeSpec type that created it. This extension is meant for debugging and should not be depended on. - -## Decorators - -### Autorest - -- [`@useRef`](#@useref) - -#### `@useRef` - -`@useRef` - is used to replace the TypeSpec model type in emitter output with a pre-existing named OpenAPI schema such as Azure Resource Manager common types. - -`@useRef` can be specified on Models and ModelProperty. - -```typespec -@Autorest.useRef(jsonRef: valueof string) -``` - -##### Target - -`Model | ModelProperty` - -##### Parameters - -| Name | Type | Description | -| ------- | ---------------- | --------------------------------- | -| jsonRef | `valueof string` | path or Uri to an OpenAPI schema. | diff --git a/packages/typespec-autorest-canonical/lib/autorest-canonical.tsp b/packages/typespec-autorest-canonical/lib/autorest-canonical.tsp index 9ee8dde558..06847d5a6d 100644 --- a/packages/typespec-autorest-canonical/lib/autorest-canonical.tsp +++ b/packages/typespec-autorest-canonical/lib/autorest-canonical.tsp @@ -1,2 +1 @@ -import "./decorators.tsp"; import "../dist/src/index.js"; diff --git a/packages/typespec-autorest-canonical/lib/decorators.tsp b/packages/typespec-autorest-canonical/lib/decorators.tsp deleted file mode 100644 index 8e70b996a1..0000000000 --- a/packages/typespec-autorest-canonical/lib/decorators.tsp +++ /dev/null @@ -1,12 +0,0 @@ -using TypeSpec.Reflection; - -namespace AutorestCanonical; - -/** - * `@useRef` - is used to replace the TypeSpec model type in emitter output with a pre-existing named OpenAPI schema such as Azure Resource Manager common types. - * - * `@useRef` can be specified on Models and ModelProperty. - * - * @param jsonRef - path or Uri to an OpenAPI schema. - */ -extern dec useRef(entity: Model | ModelProperty, jsonRef: valueof string); diff --git a/packages/typespec-autorest-canonical/src/decorators.ts b/packages/typespec-autorest-canonical/src/decorators.ts index 634f076905..f600863a4b 100644 --- a/packages/typespec-autorest-canonical/src/decorators.ts +++ b/packages/typespec-autorest-canonical/src/decorators.ts @@ -1,4 +1,4 @@ -import { DecoratorContext, Model, ModelProperty, Program, Service, Type } from "@typespec/compiler"; +import { Model, ModelProperty, Program, Service, Type } from "@typespec/compiler"; import { createStateSymbol } from "./lib.js"; export const namespace = "AutorestCanonical"; @@ -22,32 +22,6 @@ export type RefProducer = ( ) => string | undefined; const refTargetsKey = createStateSymbol("autorestcanonical.ref"); -/** - * `@useRef` - is used to replace the TypeSpec model type in emitter output with a pre-existing named OpenAPI schema such as ARM common types. - * - * @param {string} param jsonRef - path or Uri to an OpenAPI schema. - * - * `@useRef` can be specified on Models and ModelProperty. - */ -export function $useRef(context: DecoratorContext, entity: Model | ModelProperty, jsonRef: string) { - context.program.stateMap(refTargetsKey).set(entity, jsonRef); -} - -/** - * Configures a "ref producer" for the given entity. A ref producer is a - * function that returns a ref path for the given entity, possibly altered by - * the options provided to the function (like the service and version). - * - * @param {function} param producer - path or Uri to an OpenAPI schema. - * - */ -export function setRefProducer( - program: Program, - entity: Model | ModelProperty, - refProducer: RefProducer -) { - program.stateMap(refTargetsKey).set(entity, refProducer); -} export function getRef( program: Program, diff --git a/packages/typespec-autorest-canonical/test/decorators.test.ts b/packages/typespec-autorest-canonical/test/decorators.test.ts index d5f0f05274..60221b3ebc 100644 --- a/packages/typespec-autorest-canonical/test/decorators.test.ts +++ b/packages/typespec-autorest-canonical/test/decorators.test.ts @@ -1,11 +1,9 @@ import { getAsEmbeddingVector } from "@azure-tools/typespec-azure-core"; -import { Model, Namespace, Scalar, resolvePath } from "@typespec/compiler"; -import { BasicTestRunner, expectDiagnosticEmpty, expectDiagnostics, resolveVirtualPath } from "@typespec/compiler/testing"; +import { Model, Namespace, Scalar } from "@typespec/compiler"; +import { BasicTestRunner } from "@typespec/compiler/testing"; import { deepStrictEqual, strictEqual } from "assert"; import { beforeEach, describe, it } from "vitest"; -import { createAutorestCanonicalTestRunner, ignoreDiagnostics, ignoreUseStandardOps, openApiFor } from "./test-host.js"; -import { AutorestCanonicalTestLibrary } from "../src/testing/index.js"; -import { getRef } from "../src/decorators.js"; +import { createAutorestCanonicalTestRunner, openApiFor } from "./test-host.js"; let runner: BasicTestRunner; @@ -54,115 +52,3 @@ describe("@operationId", () => { deepStrictEqual(openapi.paths["/"].get.operationId, "Pets_GET"); }); }); - -describe("@useRef", () => { - it("emit diagnostic if use on non model or property", async () => { - const diagnostics = await runner.diagnose(` - @useRef("foo") - op foo(): string; - `); - - expectDiagnostics(ignoreUseStandardOps(diagnostics), { - code: "decorator-wrong-target", - message: - "Cannot apply @useRef decorator to foo since it is not assignable to Model | ModelProperty", - }); - }); - - it("emit diagnostic if ref is not a string", async () => { - const diagnostics = await runner.diagnose(` - @useRef(123) - model Foo {} - `); - - expectDiagnostics(ignoreUseStandardOps(diagnostics), { - code: "invalid-argument", - message: "Argument '123' is not assignable to parameter of type 'valueof string'", - }); - }); - - it("emit diagnostic if ref is not passed", async () => { - const diagnostics = await runner.diagnose(` - @useRef - model Foo {} - `); - - expectDiagnostics(ignoreUseStandardOps(diagnostics), [ - { - code: "invalid-argument-count", - message: "Expected 1 arguments, but got 0.", - }, - ]); - }); - - it("set external reference", async () => { - const [{ Foo }, diagnostics] = await runner.compileAndDiagnose(` - @test @useRef("../common.json#/definitions/Foo") - model Foo {} - `); - - expectDiagnosticEmpty( - ignoreDiagnostics(diagnostics, [ - "@azure-tools/typespec-azure-core/use-standard-operations", - "@typespec/http/no-service-found", - ]) - ); - - strictEqual(getRef(runner.program, Foo), "../common.json#/definitions/Foo"); - }); - - describe("interpolate arm-types-dir", () => { - async function testArmTypesDir(options?: any) { - const code = ` - @test @useRef("{arm-types-dir}/common.json#/definitions/Foo") - model Foo {} - - model Bar { - foo: Foo; - } - `; - const runner = await createAutorestCanonicalTestRunner(); - const outputDir = resolveVirtualPath(`specification/org/service/output`); - const diagnostics = await runner.diagnose(code, { - noEmit: false, - config: resolveVirtualPath("specification/org/service/tspconfig.json"), - emitters: { - [AutorestCanonicalTestLibrary.name]: { - ...options, - "emitter-output-dir": outputDir, - }, - }, - }); - - expectDiagnosticEmpty( - ignoreDiagnostics(diagnostics, [ - "@azure-tools/typespec-azure-core/use-standard-operations", - "@typespec/http/no-service-found", - ]) - ); - - const outPath = resolvePath(outputDir, "canonical/openapi.json"); - const openAPI = JSON.parse(runner.fs.get(outPath)!); - return openAPI.definitions.Bar.properties.foo.$ref; - } - // project-root resolve to "" in test - it("To ${project-root}../../ by default", async () => { - const ref = await testArmTypesDir(); - strictEqual(ref, "../../../../common-types/resource-management/common.json#/definitions/Foo"); - }); - - it("configure a new absolute value", async () => { - const ref = await testArmTypesDir({ - "arm-types-dir": "{project-root}/../other/path", - }); - strictEqual(ref, "../../../other/path/common.json#/definitions/Foo"); - }); - - it("keeps relative value as it is", async () => { - const ref = await testArmTypesDir({ - "arm-types-dir": "../other/path", - }); - strictEqual(ref, "../other/path/common.json#/definitions/Foo"); - }); - }); -}); From 1bbf033ad955a3315a1e468e9d604847980d9b4e Mon Sep 17 00:00:00 2001 From: Ding Date: Wed, 17 Apr 2024 11:39:24 -0700 Subject: [PATCH 3/9] prettier fix --- packages/typespec-autorest-canonical/src/openapi.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/typespec-autorest-canonical/src/openapi.ts b/packages/typespec-autorest-canonical/src/openapi.ts index c052f7f310..50f57ce7e4 100644 --- a/packages/typespec-autorest-canonical/src/openapi.ts +++ b/packages/typespec-autorest-canonical/src/openapi.ts @@ -127,6 +127,7 @@ import { getVersion, } from "@typespec/versioning"; import { AutorestCanonicalOpenAPISchema } from "./autorest-canonical-openapi-schema.js"; +import { getRef } from "./decorators.js"; import { sortWithJsonSchema } from "./json-schema-sorter/sorter.js"; import { AutorestCanonicalEmitterOptions, getTracer, reportDiagnostic } from "./lib.js"; import { @@ -148,7 +149,6 @@ import { Refable, } from "./types.js"; import { AutorestCanonicalEmitterContext, resolveOperationId } from "./utils.js"; -import { getRef } from "./decorators.js"; const defaultOptions = { "output-file": "{azure-resource-provider-folder}/{service-name}/{version}/openapi.json", From 53540de0997683bb0d39d3d58fe8e97fb0365b91 Mon Sep 17 00:00:00 2001 From: Ding Date: Wed, 17 Apr 2024 13:17:46 -0700 Subject: [PATCH 4/9] call getRef from autorest emitter --- ...date-resolveRef-2024-2024-4-17-11-10-36.md | 2 +- .../typespec-autorest-canonical/package.json | 3 +- .../src/decorators.ts | 37 ------------------- .../typespec-autorest-canonical/src/index.ts | 1 - .../src/openapi.ts | 3 +- 5 files changed, 5 insertions(+), 41 deletions(-) delete mode 100644 packages/typespec-autorest-canonical/src/decorators.ts diff --git a/.chronus/changes/update-resolveRef-2024-2024-4-17-11-10-36.md b/.chronus/changes/update-resolveRef-2024-2024-4-17-11-10-36.md index b9d95173a0..17e208fecd 100644 --- a/.chronus/changes/update-resolveRef-2024-2024-4-17-11-10-36.md +++ b/.chronus/changes/update-resolveRef-2024-2024-4-17-11-10-36.md @@ -1,6 +1,6 @@ --- # Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking -changeKind: fix +changeKind: feature packages: - "@azure-tools/typespec-autorest-canonical" --- diff --git a/packages/typespec-autorest-canonical/package.json b/packages/typespec-autorest-canonical/package.json index a65b21926e..cf2e8ba3c8 100644 --- a/packages/typespec-autorest-canonical/package.json +++ b/packages/typespec-autorest-canonical/package.json @@ -56,7 +56,8 @@ "peerDependencies": { "@azure-tools/typespec-azure-core": "workspace:~", "@azure-tools/typespec-client-generator-core": "workspace:~", - "@typespec/versioning": "workspace:~" + "@typespec/versioning": "workspace:~", + "@azure-tools/typespec-autorest": "workspace:~" }, "devDependencies": { "@azure-tools/typespec-azure-core": "workspace:~", diff --git a/packages/typespec-autorest-canonical/src/decorators.ts b/packages/typespec-autorest-canonical/src/decorators.ts deleted file mode 100644 index f600863a4b..0000000000 --- a/packages/typespec-autorest-canonical/src/decorators.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Model, ModelProperty, Program, Service, Type } from "@typespec/compiler"; -import { createStateSymbol } from "./lib.js"; - -export const namespace = "AutorestCanonical"; - -/** - * Parameters that may be passed to a RefProducer function. Specific RefProducer - * functions may define additional parameters. - */ -export interface RefProducerParams { - service?: Service; - version?: string; -} - -/** - * A function that can produce a ref path at the time it is requested. - */ -export type RefProducer = ( - program: Program, - entity: Model | ModelProperty, - params: RefProducerParams -) => string | undefined; - -const refTargetsKey = createStateSymbol("autorestcanonical.ref"); - -export function getRef( - program: Program, - entity: Type, - params?: RefProducerParams -): string | undefined { - const refOrProducer = program.stateMap(refTargetsKey).get(entity); - if (typeof refOrProducer === "function") { - return refOrProducer(program, entity, params ?? {}); - } else { - return refOrProducer; - } -} diff --git a/packages/typespec-autorest-canonical/src/index.ts b/packages/typespec-autorest-canonical/src/index.ts index 9088729ddd..64231b619f 100644 --- a/packages/typespec-autorest-canonical/src/index.ts +++ b/packages/typespec-autorest-canonical/src/index.ts @@ -1,3 +1,2 @@ -export * from "./decorators.js"; export { $lib, AutorestCanonicalEmitterOptions } from "./lib.js"; export * from "./openapi.js"; diff --git a/packages/typespec-autorest-canonical/src/openapi.ts b/packages/typespec-autorest-canonical/src/openapi.ts index 50f57ce7e4..a73c93345d 100644 --- a/packages/typespec-autorest-canonical/src/openapi.ts +++ b/packages/typespec-autorest-canonical/src/openapi.ts @@ -1,3 +1,4 @@ +import { getRef } from "@azure-tools/typespec-autorest"; import { PagedResultMetadata, UnionEnum, @@ -127,7 +128,6 @@ import { getVersion, } from "@typespec/versioning"; import { AutorestCanonicalOpenAPISchema } from "./autorest-canonical-openapi-schema.js"; -import { getRef } from "./decorators.js"; import { sortWithJsonSchema } from "./json-schema-sorter/sorter.js"; import { AutorestCanonicalEmitterOptions, getTracer, reportDiagnostic } from "./lib.js"; import { @@ -162,6 +162,7 @@ enum UnsupportedVersioningDecorators { TypeChangedFrom = "typeChangedFrom", } +export const namespace = "AutorestCanonical"; export const canonicalVersion = "canonical"; export async function $onEmit(context: EmitContext) { From 792e07c43f55c4e93e018a479006e86f12cb0628 Mon Sep 17 00:00:00 2001 From: Ding Date: Wed, 17 Apr 2024 16:35:41 -0700 Subject: [PATCH 5/9] resolve conflict --- packages/typespec-autorest-canonical/src/openapi.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/typespec-autorest-canonical/src/openapi.ts b/packages/typespec-autorest-canonical/src/openapi.ts index 84a4f8ce4f..24a1a42bfa 100644 --- a/packages/typespec-autorest-canonical/src/openapi.ts +++ b/packages/typespec-autorest-canonical/src/openapi.ts @@ -862,7 +862,7 @@ function createOAPIEmitter( return getRelativePathFromDirectory(getDirectoryPath(outputFile), absoluteRef, false); } - function getSchemaOrRef(type: Type, visibility: Visibility): any { + function getSchemaOrRef(type: Type, schemaContext: SchemaContext): any { const refUrl = getRef(program, type, { version: context.version, service: context.service }); if (refUrl) { return { From 5885c167c9d7d670ebd3574f1d6cd9cdb6c53017 Mon Sep 17 00:00:00 2001 From: Ding Date: Fri, 19 Apr 2024 07:59:47 -0700 Subject: [PATCH 6/9] fix build error --- .../typespec-autorest-canonical/reference/emitter.md | 6 ++++++ packages/typespec-autorest-canonical/README.md | 12 ++++++------ pnpm-lock.yaml | 4 ++++ 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/docs/emitters/typespec-autorest-canonical/reference/emitter.md b/docs/emitters/typespec-autorest-canonical/reference/emitter.md index 11cd57e081..4613b5348f 100644 --- a/docs/emitters/typespec-autorest-canonical/reference/emitter.md +++ b/docs/emitters/typespec-autorest-canonical/reference/emitter.md @@ -48,6 +48,12 @@ Example: Multiple services **Type:** `string` +### `arm-types-dir` + +**Type:** `string` + +Path to the common-types.json file folder. Default: '${project-root}/../../common-types/resource-management' + ### `new-line` **Type:** `"crlf" | "lf"` diff --git a/packages/typespec-autorest-canonical/README.md b/packages/typespec-autorest-canonical/README.md index 7e662b0d8e..b11edfc352 100644 --- a/packages/typespec-autorest-canonical/README.md +++ b/packages/typespec-autorest-canonical/README.md @@ -52,18 +52,18 @@ Example: Multiple services **Type:** `string` -#### `new-line` - -**Type:** `"crlf" | "lf"` - -Set the newline character for emitting files. - #### `arm-types-dir` **Type:** `string` Path to the common-types.json file folder. Default: '${project-root}/../../common-types/resource-management' +#### `new-line` + +**Type:** `"crlf" | "lf"` + +Set the newline character for emitting files. + #### `omit-unreachable-types` **Type:** `boolean` diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4fe0412118..11baa69d20 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1618,6 +1618,10 @@ importers: version: 1.5.0(@types/node@18.11.19)(@vitest/ui@1.5.0)(happy-dom@14.7.1) packages/typespec-autorest-canonical: + dependencies: + '@azure-tools/typespec-autorest': + specifier: workspace:~ + version: link:../typespec-autorest devDependencies: '@azure-tools/typespec-azure-core': specifier: workspace:~ From a8d96039f23564a9d980457baf951ef2896c9257 Mon Sep 17 00:00:00 2001 From: Ding Date: Fri, 19 Apr 2024 09:21:43 -0700 Subject: [PATCH 7/9] update --- packages/typespec-autorest-canonical/src/openapi.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/typespec-autorest-canonical/src/openapi.ts b/packages/typespec-autorest-canonical/src/openapi.ts index 24a1a42bfa..7da99b8b73 100644 --- a/packages/typespec-autorest-canonical/src/openapi.ts +++ b/packages/typespec-autorest-canonical/src/openapi.ts @@ -168,8 +168,8 @@ enum UnsupportedVersioningDecorators { TypeChangedFrom = "typeChangedFrom", } -export const namespace = "AutorestCanonical"; export const canonicalVersion = "canonical"; +export const namespace = "AutorestCanonical"; export async function $onEmit(context: EmitContext) { const resolvedOptions = { ...defaultOptions, ...context.options }; From 53c74870bdc1858dd177768e19b0e27f96e7e52e Mon Sep 17 00:00:00 2001 From: Ding Date: Fri, 19 Apr 2024 09:29:43 -0700 Subject: [PATCH 8/9] update dependencies --- packages/typespec-autorest-canonical/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/typespec-autorest-canonical/package.json b/packages/typespec-autorest-canonical/package.json index cf2e8ba3c8..4ee6d2d49a 100644 --- a/packages/typespec-autorest-canonical/package.json +++ b/packages/typespec-autorest-canonical/package.json @@ -60,6 +60,7 @@ "@azure-tools/typespec-autorest": "workspace:~" }, "devDependencies": { + "@azure-tools/typespec-autorest": "workspace:~", "@azure-tools/typespec-azure-core": "workspace:~", "@azure-tools/typespec-client-generator-core": "workspace:~", "@types/node": "~18.11.19", From fe225a391b7654a2d1914c708b27f6cf00865081 Mon Sep 17 00:00:00 2001 From: Ding Date: Fri, 19 Apr 2024 09:34:54 -0700 Subject: [PATCH 9/9] update pnpm-lock --- pnpm-lock.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 11baa69d20..7e404b6f4f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1618,11 +1618,10 @@ importers: version: 1.5.0(@types/node@18.11.19)(@vitest/ui@1.5.0)(happy-dom@14.7.1) packages/typespec-autorest-canonical: - dependencies: + devDependencies: '@azure-tools/typespec-autorest': specifier: workspace:~ version: link:../typespec-autorest - devDependencies: '@azure-tools/typespec-azure-core': specifier: workspace:~ version: link:../typespec-azure-core