Skip to content

Commit

Permalink
feat: add basic support for example tag (#1200)
Browse files Browse the repository at this point in the history
  • Loading branch information
hmil committed Mar 30, 2022
1 parent be973c0 commit fad197f
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 0 deletions.
35 changes: 35 additions & 0 deletions src/AnnotationsReader/ExtendedAnnotationsReader.ts
@@ -1,3 +1,4 @@
import json5 from "json5";
import ts from "typescript";
import { Annotations } from "../Type/AnnotatedType";
import { symbolAtNode } from "../Utils/symbolAtNode";
Expand All @@ -12,6 +13,7 @@ export class ExtendedAnnotationsReader extends BasicAnnotationsReader {
const annotations: Annotations = {
...this.getDescriptionAnnotation(node),
...this.getTypeAnnotation(node),
...this.getExampleAnnotation(node),
...super.getAnnotations(node),
};
return Object.keys(annotations).length ? annotations : undefined;
Expand Down Expand Up @@ -70,4 +72,37 @@ export class ExtendedAnnotationsReader extends BasicAnnotationsReader {
const text = (jsDocTag.text ?? []).map((part) => part.text).join("");
return { type: text };
}
/**
* Attempts to gather examples from the @-example jsdoc tag.
* See https://tsdoc.org/pages/tags/example/
*/
private getExampleAnnotation(node: ts.Node): Annotations | undefined {
const symbol = symbolAtNode(node);
if (!symbol) {
return undefined;
}

const jsDocTags: ts.JSDocTagInfo[] = symbol.getJsDocTags();
if (!jsDocTags || !jsDocTags.length) {
return undefined;
}

const examples: unknown[] = [];
for (const example of jsDocTags.filter((tag) => tag.name === "example")) {
const text = (example.text ?? []).map((part) => part.text).join("");
try {
examples.push(json5.parse(text));
} catch (e) {
// ignore examples which don't parse to valid JSON
// This could be improved to support a broader range of usages,
// such as if the example has a title (as explained in the tsdoc spec).
}
}

if (examples.length === 0) {
return undefined;
}

return { examples };
}
}
2 changes: 2 additions & 0 deletions test/valid-data-annotations.test.ts
Expand Up @@ -33,6 +33,8 @@ describe("valid-data-annotations", () => {

it("annotation-comment", assertValidSchema("annotation-comment", "MyObject", "extended"));

it("annotation-example", assertValidSchema("annotation-example", "MyObject", "extended"));

it("annotation-id", assertValidSchema("annotation-id", "MyObject", "extended", [], "Test"));

it("annotation-readOnly", assertValidSchema("annotation-readOnly", "MyObject", "basic"));
Expand Down
32 changes: 32 additions & 0 deletions test/valid-data/annotation-example/main.ts
@@ -0,0 +1,32 @@
/**
* @example
* {
* "nested": "hello"
* }
*
* @example An invalid example
* {
* "nested": "world"
* }
* @example Another invalid example
* ```ts
* {
* "nested": "world"
* }
* ```
*/
export interface MyObject {
/**
* @example
* "Hello world"
* @example
* "This string rocks"
*/
nested: MyNestedObject
}

/**
* @example With a string
* "Hello string"
*/
export type MyNestedObject = string;
28 changes: 28 additions & 0 deletions test/valid-data/annotation-example/schema.json
@@ -0,0 +1,28 @@
{
"$ref": "#/definitions/MyObject",
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"MyNestedObject": {
"type": "string"
},
"MyObject": {
"examples": [
{ "nested": "hello" }
],
"additionalProperties": false,
"properties": {
"nested": {
"examples": [
"Hello world",
"This string rocks"
],
"$ref": "#/definitions/MyNestedObject"
}
},
"required": [
"nested"
],
"type": "object"
}
}
}

0 comments on commit fad197f

Please sign in to comment.