Skip to content

Commit 06c44c1

Browse files
authored
fix(core): emit nested array item constraints in jsdoc (#3357)
1 parent 0ea5571 commit 06c44c1

4 files changed

Lines changed: 104 additions & 0 deletions

File tree

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { describe, expect, it } from 'vitest';
2+
3+
import { jsDoc } from './doc';
4+
5+
describe('jsDoc', () => {
6+
it('includes validators from array items', () => {
7+
expect(
8+
jsDoc({
9+
type: 'array',
10+
maxItems: 20,
11+
items: {
12+
type: 'string',
13+
maxLength: 50,
14+
pattern: '^[a-z]+$',
15+
},
16+
}),
17+
).toBe(`/**
18+
* @maxItems 20
19+
* @items.maxLength 50
20+
* @items.pattern ^[a-z]+$
21+
*/
22+
`);
23+
});
24+
25+
it('includes validators from nested array items', () => {
26+
expect(
27+
jsDoc({
28+
type: 'array',
29+
items: {
30+
type: 'array',
31+
minItems: 2,
32+
maxItems: 5,
33+
items: {
34+
type: 'string',
35+
minLength: 1,
36+
},
37+
},
38+
}),
39+
).toBe(`/**
40+
* @items.minItems 2
41+
* @items.maxItems 5
42+
* @items.items.minLength 1
43+
*/
44+
`);
45+
});
46+
});

packages/core/src/utils/doc.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,44 @@ interface JsDocSchema extends Record<string, unknown> {
1919
maxItems?: number;
2020
type?: string | string[];
2121
pattern?: string;
22+
items?: JsDocSchema;
23+
}
24+
25+
interface JsDocEntry {
26+
key: string;
27+
value: boolean | number | string;
28+
}
29+
30+
const itemValidationKeys = [
31+
'minLength',
32+
'maxLength',
33+
'minimum',
34+
'maximum',
35+
'exclusiveMinimum',
36+
'exclusiveMaximum',
37+
'minItems',
38+
'maxItems',
39+
'pattern',
40+
] as const satisfies readonly (keyof JsDocSchema)[];
41+
42+
function getItemValidationDocEntries(
43+
schema?: JsDocSchema,
44+
prefix = 'items',
45+
): JsDocEntry[] {
46+
if (!schema) {
47+
return [];
48+
}
49+
50+
const entries = itemValidationKeys.flatMap((key) => {
51+
const value = schema[key];
52+
53+
return value === undefined ? [] : [{ key: `${prefix}.${key}`, value }];
54+
});
55+
56+
return [
57+
...entries,
58+
...getItemValidationDocEntries(schema.items, `${prefix}.items`),
59+
];
2260
}
2361

2462
export function jsDoc(
@@ -49,6 +87,7 @@ export function jsDoc(
4987
const isNullable =
5088
schema.type === 'null' ||
5189
(Array.isArray(schema.type) && schema.type.includes('null'));
90+
const itemValidationDocEntries = getItemValidationDocEntries(schema.items);
5291
// Ensure there aren't any comment terminations in doc
5392
const lines = (
5493
Array.isArray(description)
@@ -70,6 +109,7 @@ export function jsDoc(
70109
maxItems?.toString(),
71110
isNullable ? 'null' : '',
72111
pattern,
112+
...itemValidationDocEntries.map(({ value }) => value.toString()),
73113
].filter(Boolean).length;
74114

75115
if (!count) {
@@ -131,6 +171,18 @@ export function jsDoc(
131171
tryAppendBooleanDocLine('nullable', isNullable);
132172
tryAppendStringDocLine('pattern', pattern);
133173

174+
for (const { key, value } of itemValidationDocEntries) {
175+
if (typeof value === 'string') {
176+
tryAppendStringDocLine(key, value);
177+
continue;
178+
}
179+
if (typeof value === 'number') {
180+
tryAppendNumberDocLine(key, value);
181+
continue;
182+
}
183+
tryAppendBooleanDocLine(key, value);
184+
}
185+
134186
doc += oneLine ? ' ' : `\n ${tryOneLine ? ' ' : ''}`;
135187

136188
doc += '*/\n';

tests/__snapshots__/mock/circular/model/addListBody.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ export type AddListBody = {
99
/**
1010
* @minItems 1
1111
* @maxItems 10
12+
* @items.minimum 1
13+
* @items.maximum 10
1214
*/
1315
list: number[];
1416
};

tests/__snapshots__/swr/nested-arrays/model/resSampleModel.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,9 @@
66
*/
77

88
export interface ResSampleModel {
9+
/**
10+
* @items.minItems 2
11+
* @items.maxItems 5
12+
*/
913
items: string[][];
1014
}

0 commit comments

Comments
 (0)