Skip to content

Commit

Permalink
feat: Add option to generate markdownDescription (#1773)
Browse files Browse the repository at this point in the history
fixes #1544
  • Loading branch information
Jason3S committed Oct 16, 2023
1 parent 47eb93c commit 2ec470e
Show file tree
Hide file tree
Showing 7 changed files with 238 additions and 10 deletions.
5 changes: 4 additions & 1 deletion factory/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,10 @@ export function createParser(program: ts.Program, config: Config, augmentor?: Pa
function withJsDoc(nodeParser: SubNodeParser): SubNodeParser {
const extraTags = new Set(mergedConfig.extraTags);
if (mergedConfig.jsDoc === "extended") {
return new AnnotatedNodeParser(nodeParser, new ExtendedAnnotationsReader(typeChecker, extraTags));
return new AnnotatedNodeParser(
nodeParser,
new ExtendedAnnotationsReader(typeChecker, extraTags, mergedConfig.markdownDescription)
);
} else if (mergedConfig.jsDoc === "basic") {
return new AnnotatedNodeParser(nodeParser, new BasicAnnotationsReader(extraTags));
} else {
Expand Down
19 changes: 11 additions & 8 deletions src/AnnotationsReader/ExtendedAnnotationsReader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import { BasicAnnotationsReader } from "./BasicAnnotationsReader";
export class ExtendedAnnotationsReader extends BasicAnnotationsReader {
public constructor(
private typeChecker: ts.TypeChecker,
extraTags?: Set<string>
extraTags?: Set<string>,
private markdownDescription?: boolean
) {
super(extraTags);
}
Expand Down Expand Up @@ -48,13 +49,15 @@ export class ExtendedAnnotationsReader extends BasicAnnotationsReader {
return undefined;
}

return {
description: comments
.map((comment) => comment.text.replace(/\r/g, "").replace(/(?<=[^\n])\n(?=[^\n*-])/g, " "))
.join(" ")
// strip newlines
.replace(/^\s+|\s+$/g, ""),
};
const markdownDescription = comments
.map((comment) => comment.text)
.join(" ")
.replace(/\r/g, "")
.trim();

const description = markdownDescription.replace(/(?<=[^\n])\n(?=[^\n*-])/g, " ").trim();

return this.markdownDescription ? { description, markdownDescription } : { description };
}
private getTypeAnnotation(node: ts.Node): Annotations | undefined {
const symbol = symbolAtNode(node);
Expand Down
2 changes: 2 additions & 0 deletions src/Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export interface Config {
expose?: "all" | "none" | "export";
topRef?: boolean;
jsDoc?: "none" | "extended" | "basic";
markdownDescription?: boolean;
sortProps?: boolean;
strictTuples?: boolean;
skipTypeCheck?: boolean;
Expand All @@ -20,6 +21,7 @@ export const DEFAULT_CONFIG: Omit<Required<Config>, "path" | "type" | "schemaId"
expose: "export",
topRef: true,
jsDoc: "extended",
markdownDescription: false,
sortProps: true,
strictTuples: false,
skipTypeCheck: false,
Expand Down
13 changes: 12 additions & 1 deletion test/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ function assertSchema(
const validator = new Ajv({
// skip full check if we are not encoding refs
validateFormats: config.encodeRefs === false ? undefined : true,
keywords: config.markdownDescription ? ["markdownDescription"] : undefined,
});

addFormats(validator);
Expand Down Expand Up @@ -317,7 +318,17 @@ describe("config", () => {
skipTypeCheck: true,
})
);

it(
"markdown-description",
assertSchema("markdown-description", {
type: "MyObject",
expose: "export",
topRef: false,
jsDoc: "extended",
sortProps: true,
markdownDescription: true,
})
);
it(
"tsconfig-support",
assertSchema(
Expand Down
97 changes: 97 additions & 0 deletions test/config/markdown-description/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/**
* @title Some title here
* @description Some description here
*/
export interface MyObject {
/**
* @title String field title
* @minLength 10
* @format date-time
* @pattern /^\d+$/
*/
stringValue: string;

/**
* @title Required value
*/
requiredValue: number | string;
/**
* @title Nullable value
*/
nullableValue: number | string |null;
/**
* @title Optional value
*/
optionalValue: number | string | undefined;

/**
* Some ignored comment description
*
* @description Export field description
* @default {"length": 10}
* @nullable
*/
exportString: MyExportString;
/**
* @description Export field description
* @default "private"
*/
privateString: MyPrivateString;

/**
* @title Non empty array
*/
numberArray: MyNonEmptyArray<number>;

/**
* @nullable
*/
number: number;

/**
* Some more examples:
* ```yaml
* name: description
* length: 42
* ```
*/
description: InheritedExample['description'];

/**
* @default ""
*/
inheritedDescription: InheritedExample['description'];
}

/**
* @title My export string
*/
export type MyExportString = string;
/**
* @title My private string
*/
type MyPrivateString = string;
/**
* @minItems 1
*/
export type MyNonEmptyArray<T> = T[];

interface InheritedExample {
/**
* We have a bit more text.
*
* Usage: It is possible to add markdown in the JSDoc comment.
*
* ```ts
* // comment
* async function readFile(path: string): Promise<string>;
* ```
*
* It is stored raw.
* @title description
*
* More comments.
*
*/
description: string;
}
106 changes: 106 additions & 0 deletions test/config/markdown-description/schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"definitions": {
"MyExportString": {
"title": "My export string",
"type": "string"
},
"MyNonEmptyArray<number>": {
"items": {
"type": "number"
},
"minItems": 1,
"type": "array"
}
},
"description": "Some description here",
"properties": {
"description": {
"description": "Some more examples: ```yaml name: description length: 42 ```",
"markdownDescription": "Some more examples:\n```yaml\nname: description\nlength: 42\n```",
"title": "description\n\nMore comments.",
"type": "string"
},
"exportString": {
"anyOf": [
{
"$ref": "#/definitions/MyExportString",
"markdownDescription": "Some ignored comment description"
},
{
"type": "null"
}
],
"default": {
"length": 10
},
"description": "Export field description"
},
"inheritedDescription": {
"default": "",
"description": "We have a bit more text.\n\nUsage: It is possible to add markdown in the JSDoc comment.\n\n```ts // comment async function readFile(path: string): Promise<string>; ```\n\nIt is stored raw.",
"markdownDescription": "We have a bit more text.\n\nUsage: It is possible to add markdown in the JSDoc comment.\n\n```ts\n// comment\nasync function readFile(path: string): Promise<string>;\n```\n\nIt is stored raw.",
"title": "description\n\nMore comments.",
"type": "string"
},
"nullableValue": {
"title": "Nullable value",
"type": [
"number",
"string",
"null"
]
},
"number": {
"type": [
"number",
"null"
]
},
"numberArray": {
"$ref": "#/definitions/MyNonEmptyArray%3Cnumber%3E",
"title": "Non empty array"
},
"optionalValue": {
"title": "Optional value",
"type": [
"number",
"string"
]
},
"privateString": {
"default": "private",
"description": "Export field description",
"title": "My private string",
"type": "string"
},
"requiredValue": {
"title": "Required value",
"type": [
"number",
"string"
]
},
"stringValue": {
"format": "date-time",
"minLength": 10,
"pattern": "/^\\d+$/",
"title": "String field title",
"type": "string"
}
},
"required": [
"stringValue",
"requiredValue",
"nullableValue",
"exportString",
"privateString",
"numberArray",
"number",
"description",
"inheritedDescription"
],
"title": "Some title here",
"type": "object"
}
6 changes: 6 additions & 0 deletions ts-json-schema-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ const args = new Command()
.choices(["none", "basic", "extended"])
.default("extended")
)
.addOption(
new Option("--markdown-description", "Generate `markdownDescription` in addition to `description`.").implies({
jsDoc: "extended",
})
)
.option("--minify", "Minify generated schema", false)
.option("--unstable", "Do not sort properties")
.option("--strict-tuples", "Do not allow additional items on tuples")
Expand Down Expand Up @@ -53,6 +58,7 @@ const config: Config = {
expose: args.expose,
topRef: args.topRef,
jsDoc: args.jsDoc,
markdownDescription: args.markdownDescription,
sortProps: !args.unstable,
strictTuples: args.strictTuples,
skipTypeCheck: !args.typeCheck,
Expand Down

0 comments on commit 2ec470e

Please sign in to comment.