From ee4172a8f03d79f65f5ea3ab26c031efc1d50b4b Mon Sep 17 00:00:00 2001 From: Kyle Zhang Date: Sat, 28 Sep 2024 01:40:06 +0800 Subject: [PATCH] Fix issue: OpenAPI 3 Emitter failed to check type of termsOfService in @info (#4483) [issue 3885](https://github.com/microsoft/typespec/issues/3885) --------- Co-authored-by: Kyle Zhang Co-authored-by: Timothee Guerin --- ...rmsOfServiceUrlCheck-2024-8-23-12-59-15.md | 7 +++++++ packages/openapi/src/decorators.ts | 19 +++++++++++++++++++ packages/openapi/src/lib.ts | 6 ++++++ packages/openapi/test/decorators.test.ts | 12 ++++++++++++ 4 files changed, 44 insertions(+) create mode 100644 .chronus/changes/termsOfServiceUrlCheck-2024-8-23-12-59-15.md diff --git a/.chronus/changes/termsOfServiceUrlCheck-2024-8-23-12-59-15.md b/.chronus/changes/termsOfServiceUrlCheck-2024-8-23-12-59-15.md new file mode 100644 index 0000000000..541f10403d --- /dev/null +++ b/.chronus/changes/termsOfServiceUrlCheck-2024-8-23-12-59-15.md @@ -0,0 +1,7 @@ +--- +changeKind: fix +packages: + - "@typespec/openapi" +--- + +`@info` decorator validate `termsOfService` is a valid url \ No newline at end of file diff --git a/packages/openapi/src/decorators.ts b/packages/openapi/src/decorators.ts index d8d41ac379..bf2dae3acf 100644 --- a/packages/openapi/src/decorators.ts +++ b/packages/openapi/src/decorators.ts @@ -185,6 +185,11 @@ export const $info: InfoDecorator = ( if (data === undefined) { return; } + if (data.termsOfService) { + if (!validateIsUri(context, data.termsOfService, "TermsOfService")) { + return; + } + } setInfo(context.program, entity, data); }; @@ -214,3 +219,17 @@ export function resolveInfo(program: Program, entity: Namespace): AdditionalInfo function omitUndefined>(data: T): T { return Object.fromEntries(Object.entries(data).filter(([k, v]) => v !== undefined)) as any; } + +function validateIsUri(context: DecoratorContext, url: string, propertyName: string) { + try { + new URL(url); + return true; + } catch { + reportDiagnostic(context.program, { + code: "not-url", + target: context.getArgumentTarget(0)!, + format: { property: propertyName, value: url }, + }); + return false; + } +} diff --git a/packages/openapi/src/lib.ts b/packages/openapi/src/lib.ts index 0c5c097fba..7201672536 100644 --- a/packages/openapi/src/lib.ts +++ b/packages/openapi/src/lib.ts @@ -16,6 +16,12 @@ export const $lib = createTypeSpecLibrary({ parameter: paramMessage`Duplicate parameter key: '${"value"}'. Check @friendlyName decorators and overlap with types in TypeSpec or service namespace.`, }, }, + "not-url": { + severity: "error", + messages: { + default: paramMessage`${"property"}: ${"value"} is not a valid URL.`, + }, + }, }, }); diff --git a/packages/openapi/test/decorators.test.ts b/packages/openapi/test/decorators.test.ts index dbc2b394a3..87cf1d6b52 100644 --- a/packages/openapi/test/decorators.test.ts +++ b/packages/openapi/test/decorators.test.ts @@ -152,6 +152,18 @@ describe("openapi: decorators", () => { }); describe("@info", () => { + it("emit diagnostic if termsOfService is not a valid url", async () => { + const diagnostics = await runner.diagnose(` + @info({termsOfService:"notvalidurl"}) + @test namespace Service {} + `); + + expectDiagnostics(diagnostics, { + code: "@typespec/openapi/not-url", + message: "TermsOfService: notvalidurl is not a valid URL.", + }); + }); + it("emit diagnostic if use on non namespace", async () => { const diagnostics = await runner.diagnose(` @info({})