diff --git a/.chronus/changes/fix-examples-const-2024-8-30-17-28-17.md b/.chronus/changes/fix-examples-const-2024-8-30-17-28-17.md new file mode 100644 index 0000000000..205f0a2871 --- /dev/null +++ b/.chronus/changes/fix-examples-const-2024-8-30-17-28-17.md @@ -0,0 +1,8 @@ +--- +# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking +changeKind: fix +packages: + - "@typespec/compiler" +--- + +Fix: Passing `const` of model type to `@example` diff --git a/docs/standard-library/examples.md b/docs/standard-library/examples.md index afbfaccffb..7ee382b624 100644 --- a/docs/standard-library/examples.md +++ b/docs/standard-library/examples.md @@ -65,6 +65,18 @@ model Pet { } ``` +### Define typed examples using `const` + +```tsp +const petExample: Pet = #{ name: "Max", age: 3 }; + +@example(petExample) +model Pet { + name: string; + age: int32; +} +``` + ## Operation examples Operation example are provided with the `@opExample` decorator. Similar to the `@example` decorator the first argument is the example value however it takes both the `parameters` and `returnType` example. diff --git a/packages/compiler/src/core/checker.ts b/packages/compiler/src/core/checker.ts index 5823fccb92..07112b88b9 100644 --- a/packages/compiler/src/core/checker.ts +++ b/packages/compiler/src/core/checker.ts @@ -3921,7 +3921,6 @@ export function createChecker(program: Program): Checker { type.indexer = isBase.indexer; } } - decorators.push(...checkDecorators(type, node, mapper)); if (isBase) { for (const prop of isBase.properties.values()) { @@ -3957,6 +3956,8 @@ export function createChecker(program: Program): Checker { // Evaluate the properties after checkModelProperties(node, type.properties, type, mapper); + decorators.push(...checkDecorators(type, node, mapper)); + linkMapper(type, mapper); if (shouldCreateTypeForTemplate(node, mapper)) { diff --git a/packages/compiler/test/decorators/examples.test.ts b/packages/compiler/test/decorators/examples.test.ts index 4187243381..3a50bb5e85 100644 --- a/packages/compiler/test/decorators/examples.test.ts +++ b/packages/compiler/test/decorators/examples.test.ts @@ -47,6 +47,19 @@ describe("@example", () => { expect(serializeValueAsJson(program, examples[0].value, target)).toEqual({ a: 1, b: 2 }); }); + it("use const with type of model", async () => { + const { program, examples, target } = await getExamplesFor(` + const example: Test = #{ a: 1, b: 2 }; + @example(example) + @test("test") model Test { + a: int32; + b: int32; + } + `); + expect(examples).toHaveLength(1); + expect(serializeValueAsJson(program, examples[0].value, target)).toEqual({ a: 1, b: 2 }); + }); + it("emit diagnostic for missing property", async () => { const diagnostics = await diagnoseCode(` @example(#{ a: 1 }) @@ -98,6 +111,16 @@ describe("@example", () => { expect(serializeValueAsJson(program, examples[0].value, target)).toEqual("11:32"); }); + it("use const with type of scalar", async () => { + const { program, examples, target } = await getExamplesFor(` + const example: test = test.fromISO("11:32"); + @example(example) + @test scalar test extends utcDateTime; + `); + expect(examples).toHaveLength(1); + expect(serializeValueAsJson(program, examples[0].value, target)).toEqual("11:32"); + }); + it("emit diagnostic for unassignable value", async () => { const diagnostics = await diagnoseCode(` @example("11:32") @@ -122,6 +145,19 @@ describe("@example", () => { expect(serializeValueAsJson(program, examples[0].value, target)).toEqual("a"); }); + it("use const with type of enum", async () => { + const { program, examples, target } = await getExamplesFor(` + const example: Test = Test.a; + @example(example) + @test("test") enum Test { + a, + b, + } + `); + expect(examples).toHaveLength(1); + expect(serializeValueAsJson(program, examples[0].value, target)).toEqual("a"); + }); + it("emit diagnostic for unassignable value", async () => { const diagnostics = await diagnoseCode(` @example(1)