Skip to content

Commit

Permalink
Merge pull request #1799 from vega/next
Browse files Browse the repository at this point in the history
  • Loading branch information
domoritz authored Oct 16, 2023
2 parents 26a3556 + 2ec470e commit 35569f7
Show file tree
Hide file tree
Showing 16 changed files with 1,240 additions and 861 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/publish-auto.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:

name: Make a release and publish to NPM
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
fetch-depth: 0

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
runs-on: ${{ matrix.os }}

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- uses: actions/setup-node@v3
with:
Expand Down
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
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"json5": "^2.2.3",
"normalize-path": "^3.0.0",
"safe-stable-stringify": "^2.4.3",
"typescript": "~5.1.6"
"typescript": "~5.2.2"
},
"devDependencies": {
"@auto-it/conventional-commits": "^11.0.0",
Expand Down Expand Up @@ -92,5 +92,6 @@
"debug": "node -r ts-node/register --inspect-brk ts-json-schema-generator.ts",
"run": "ts-node-transpile-only ts-json-schema-generator.ts",
"release": "yarn build && auto shipit"
}
},
"packageManager": "[email protected]"
}
2 changes: 2 additions & 0 deletions src/AnnotationsReader/BasicAnnotationsReader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ export class BasicAnnotationsReader implements AnnotationsReader {

"default",

"required",

// New since draft-07:
"if",
"then",
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"
}
9 changes: 9 additions & 0 deletions test/valid-data-other.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { assertValidSchema } from "./utils";
import * as objectRequiredSamples from "./valid-data/object-required/samples";

describe("valid-data-other", () => {
it("enums-string", assertValidSchema("enums-string", "Enum"));
Expand Down Expand Up @@ -92,4 +93,12 @@ describe("valid-data-other", () => {
it("array-min-max-items-optional", assertValidSchema("array-min-max-items-optional", "MyType"));
it("array-max-items-optional", assertValidSchema("array-max-items-optional", "MyType"));
it("shorthand-array", assertValidSchema("shorthand-array", "MyType"));

it(
"object-required",
assertValidSchema("object-required", "MyObject", undefined, {
...objectRequiredSamples,
ajvOptions: { $data: true },
})
);
});
12 changes: 12 additions & 0 deletions test/valid-data/object-required/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* @required ["id", "keys", "definitions"]
*/
export interface MyObject {
id?: string;
keys: string[];
/**
* every element in `keys` must also be a key in `definitions`
* @required { $data: "1/keys" }
*/
definitions: Record<string, number>;
}
26 changes: 26 additions & 0 deletions test/valid-data/object-required/samples.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type { MyObject } from "./main.js";

export const validSamples: MyObject[] = [
{
id: "123",
keys: ["a", "b"],
definitions: { a: 1, b: 2 },
},
{
id: "123",
keys: [],
definitions: {},
},
];

export const invalidSamples: MyObject[] = [
{
keys: ["a", "b"],
definitions: { a: 1, b: 2 },
},
{
id: "123",
keys: ["a", "b"],
definitions: { a: 1 },
},
];
Loading

0 comments on commit 35569f7

Please sign in to comment.