diff --git a/.chronus/changes/autorest-generated-dec-sig-2024-6-18-11-30-47.md b/.chronus/changes/autorest-generated-dec-sig-2024-6-18-11-30-47.md new file mode 100644 index 0000000000..beca6404cf --- /dev/null +++ b/.chronus/changes/autorest-generated-dec-sig-2024-6-18-11-30-47.md @@ -0,0 +1,6 @@ +--- +changeKind: internal +packages: + - "@azure-tools/typespec-autorest" +--- + diff --git a/packages/typespec-autorest/generated-defs/Autorest.ts b/packages/typespec-autorest/generated-defs/Autorest.ts new file mode 100644 index 0000000000..9d05d87d54 --- /dev/null +++ b/packages/typespec-autorest/generated-defs/Autorest.ts @@ -0,0 +1,29 @@ +import type { DecoratorContext, Model, ModelProperty, Operation } from "@typespec/compiler"; + +/** + * `@example` - attaches example files to an operation. Multiple examples can be specified. + * + * `@example` can be specified on Operations. + * + * @param pathOrUri path or Uri to the example file. + * @param title name or description of the example file. + */ +export type ExampleDecorator = ( + context: DecoratorContext, + target: Operation, + pathOrUri: string, + title: string +) => void; + +/** + * `@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. + */ +export type UseRefDecorator = ( + context: DecoratorContext, + entity: Model | ModelProperty, + jsonRef: string +) => void; diff --git a/packages/typespec-autorest/generated-defs/Autorest.ts-test.ts b/packages/typespec-autorest/generated-defs/Autorest.ts-test.ts new file mode 100644 index 0000000000..56153d3333 --- /dev/null +++ b/packages/typespec-autorest/generated-defs/Autorest.ts-test.ts @@ -0,0 +1,14 @@ +/** An error here would mean that the decorator is not exported or doesn't have the right name. */ +import { $example, $useRef } from "@azure-tools/typespec-autorest"; +import type { ExampleDecorator, UseRefDecorator } from "./Autorest.js"; + +type Decorators = { + $example: ExampleDecorator; + $useRef: UseRefDecorator; +}; + +/** An error here would mean that the exported decorator is not using the same signature. Make sure to have export const $decName: DecNameDecorator = (...) => ... */ +const _: Decorators = { + $example, + $useRef, +}; diff --git a/packages/typespec-autorest/package.json b/packages/typespec-autorest/package.json index 867b998e55..e930c718a4 100644 --- a/packages/typespec-autorest/package.json +++ b/packages/typespec-autorest/package.json @@ -35,8 +35,9 @@ }, "scripts": { "clean": "rimraf ./dist ./temp", - "build": "npm run regen-autorest-openapi-schema && tsc -p . && npm run lint-typespec-library", + "build": "npm run gen-extern-signature && npm run regen-autorest-openapi-schema && tsc -p . && npm run lint-typespec-library", "watch": "tsc -p . --watch", + "gen-extern-signature": "tspd --enable-experimental gen-extern-signature .", "lint-typespec-library": "tsp compile . --warn-as-error --import @typespec/library-linter --no-emit", "regen-autorest-openapi-schema": "tsp compile ./schema/autorest-openapi-schema.tsp --warn-as-error && node ./.scripts/schema-json-to-js.js", "test": "vitest run", diff --git a/packages/typespec-autorest/src/decorators.ts b/packages/typespec-autorest/src/decorators.ts index ef306cc83c..bbdee5fbb3 100644 --- a/packages/typespec-autorest/src/decorators.ts +++ b/packages/typespec-autorest/src/decorators.ts @@ -1,5 +1,6 @@ import { DecoratorContext, Model, ModelProperty, Program, Type } from "@typespec/compiler"; -import { createStateSymbol, reportDiagnostic } from "./lib.js"; +import { ExampleDecorator, UseRefDecorator } from "../generated-defs/Autorest.js"; +import { AutorestStateKeys, reportDiagnostic } from "./lib.js"; export const namespace = "Autorest"; @@ -8,7 +9,6 @@ export interface Example { title: string; } -const exampleKey = createStateSymbol("example"); /** * `@example` - attaches example files to an operation. Multiple examples can be specified. * @@ -17,18 +17,18 @@ const exampleKey = createStateSymbol("example"); * * `@example` can be specified on Operations. */ -export function $example( +export const $example: ExampleDecorator = ( context: DecoratorContext, entity: Type, pathOrUri: string, title: string -) { +) => { const { program } = context; - if (!program.stateMap(exampleKey).has(entity)) { - program.stateMap(exampleKey).set(entity, []); + if (!program.stateMap(AutorestStateKeys.example).has(entity)) { + program.stateMap(AutorestStateKeys.example).set(entity, []); } else if ( program - .stateMap(exampleKey) + .stateMap(AutorestStateKeys.example) .get(entity) .find((e: Example) => e.title === title || e.pathOrUri === pathOrUri) ) { @@ -37,17 +37,16 @@ export function $example( target: entity, }); } - program.stateMap(exampleKey).get(entity).push({ + program.stateMap(AutorestStateKeys.example).get(entity).push({ pathOrUri, title, }); -} +}; export function getExamples(program: Program, entity: Type): Example[] | undefined { - return program.stateMap(exampleKey).get(entity); + return program.stateMap(AutorestStateKeys.example).get(entity); } -const refTargetsKey = createStateSymbol("autorest.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. * @@ -55,11 +54,15 @@ const refTargetsKey = createStateSymbol("autorest.ref"); * * `@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); -} +export const $useRef: UseRefDecorator = ( + context: DecoratorContext, + entity: Model | ModelProperty, + jsonRef: string +) => { + context.program.stateMap(AutorestStateKeys.useRef).set(entity, jsonRef); +}; export function getRef(program: Program, entity: Type): string | undefined { - const refOrProducer = program.stateMap(refTargetsKey).get(entity); + const refOrProducer = program.stateMap(AutorestStateKeys.useRef).get(entity); return refOrProducer; } diff --git a/packages/typespec-autorest/src/lib.ts b/packages/typespec-autorest/src/lib.ts index ad244a04c0..ce4f5d8ac1 100644 --- a/packages/typespec-autorest/src/lib.ts +++ b/packages/typespec-autorest/src/lib.ts @@ -223,7 +223,7 @@ const EmitterOptionsSchema: JSONSchemaType = { required: [], }; -const libDef = { +export const $lib = createTypeSpecLibrary({ name: "@azure-tools/typespec-autorest", diagnostics: { "duplicate-body-types": { @@ -343,7 +343,11 @@ const libDef = { emitter: { options: EmitterOptionsSchema as JSONSchemaType, }, -} as const; -export const $lib = createTypeSpecLibrary(libDef); -export const { reportDiagnostic, createDiagnostic, createStateSymbol, getTracer } = $lib; + state: { + example: { description: "State for the @example decorator" }, + useRef: { description: "State for the @useRef decorator" }, + }, +} as const); + +export const { reportDiagnostic, createDiagnostic, stateKeys: AutorestStateKeys, getTracer } = $lib; diff --git a/packages/typespec-autorest/tsconfig.json b/packages/typespec-autorest/tsconfig.json index b1066a5a33..c836c7b426 100644 --- a/packages/typespec-autorest/tsconfig.json +++ b/packages/typespec-autorest/tsconfig.json @@ -14,5 +14,5 @@ "rootDir": ".", "tsBuildInfoFile": "temp/tsconfig.tsbuildinfo" }, - "include": ["src/**/*.ts", "test/**/*.ts"] + "include": ["src/**/*.ts", "generated-defs/**/*.ts", "test/**/*.ts"] }