Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Core] Exempt versioning enums and discriminator enum/unions from documentation required rule #710

Merged
merged 8 commits into from
Apr 24, 2024
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
changeKind: fix
packages:
- "@azure-tools/typespec-azure-core"
---

Exempt versioning enums and discriminator enum/unions from `documentation-required` rule.
70 changes: 69 additions & 1 deletion packages/typespec-azure-core/src/rules/require-docs.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,18 @@
import { Enum, Model, Operation, createRule, getDoc, paramMessage } from "@typespec/compiler";
import {
Discriminator,
Enum,
Model,
ModelProperty,
Operation,
Program,
Union,
createRule,
getDiscriminatedTypes,
getDiscriminator,
getDoc,
paramMessage,
} from "@typespec/compiler";
import { getVersionsForEnum } from "@typespec/versioning";
import {
isExcludedCoreType,
isInlineModel,
Expand All @@ -7,6 +21,48 @@ import {
isTemplatedOperationSignature,
} from "./utils.js";

/** Versioning enums are self-documenting and don't need separate documentation. */
function isExcludedVersionEnum(program: Program, enumObj: Enum): boolean {
const versions = getVersionsForEnum(program, enumObj);
if (versions !== undefined && versions.length > 0) {
return true;
}
return false;
}

function findDiscriminator(program: Program, model?: Model): Discriminator | undefined {
if (!model) return undefined;
const disc = getDiscriminator(program, model);
if (disc) {
return disc;
}
return findDiscriminator(program, model.baseModel);
}

/** Discriminator enums and unions are self-documenting and don't need separate documentation. */
function isExcludedDiscriminator(
program: Program,
type: ModelProperty | Enum,
discTypes: [Model | Union, Discriminator][]
): boolean {
if (type.kind === "ModelProperty") {
const disc = findDiscriminator(program, type.model);
if (disc && disc.propertyName === type.name) {
return true;
}
} else if (type.kind === "Enum") {
for (const [discType, discName] of discTypes) {
if (discType.kind === "Model") {
const discObj = discType.properties.get(discName.propertyName);
if (discObj?.type === type) {
return true;
}
}
}
}
return false;
}

export const requireDocumentation = createRule({
name: "documentation-required",
description: "Require documentation over enums, models, and operations.",
Expand All @@ -15,8 +71,16 @@ export const requireDocumentation = createRule({
default: paramMessage`The ${"kind"} named '${"name"}' should have a documentation or description, use doc comment /** */ to provide it.`,
},
create(context) {
const discTypes = getDiscriminatedTypes(context.program);
return {
enum: (enumObj: Enum) => {
// version enums and enum members are considered intrinsically self-documenting
if (isExcludedVersionEnum(context.program, enumObj)) {
return;
}
if (isExcludedDiscriminator(context.program, enumObj, discTypes)) {
return;
}
if (!getDoc(context.program, enumObj) && !isExcludedCoreType(context.program, enumObj)) {
context.reportDiagnostic({
target: enumObj,
Expand Down Expand Up @@ -72,6 +136,10 @@ export const requireDocumentation = createRule({
});
}
for (const prop of model.properties.values()) {
// Properties that are discriminators are considered self-documenting
if (isExcludedDiscriminator(context.program, prop, discTypes)) {
return;
}
if (!getDoc(context.program, prop)) {
context.reportDiagnostic({
target: prop,
Expand Down
64 changes: 64 additions & 0 deletions packages/typespec-azure-core/test/rules/require-docs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,5 +74,69 @@ describe("typespec-azure-core: documentation-required rule", () => {
"The EnumMember named 'Bar' should have a documentation or description, use doc comment /** */ to provide it."
);
});

it("does not require documentation on version enums", async () => {
await tester
.expect(
`
@versioned(Contoso.WidgetManager.Versions)
namespace Contoso.WidgetManager;

enum Versions {
@useDependency(Azure.Core.Versions.v1_0_Preview_2)
"2022-08-30",
}`
)
.toBeValid();
});

it("does not require documentation on discriminator enums", async () => {
await tester
.expect(
`
enum PetKind {
cat,
dog,
}

@discriminator("kind")
@doc("Base Pet model")
model Pet {
kind: PetKind;

@doc("Pet name")
name: string;
}

@doc("A Cat")
model Cat extends Pet {
kind: PetKind.cat;
}`
)
.toBeValid();
});

it("does not require documentation on discriminator unions", async () => {
await tester
.expect(
`
union PetKind {
cat: "cat",
string,
}

@discriminator("kind")
@doc("Base Pet model")
model Pet {
kind: PetKind;
}

@doc("A Merry Ol' Cat")
model Cat extends Pet {
kind: PetKind.cat,
}`
)
.toBeValid();
});
});
});
Loading