Skip to content

Commit 9b76726

Browse files
committed
Refactor JSON schema definitions and add type guards
1 parent 098dc85 commit 9b76726

File tree

2 files changed

+286
-31
lines changed

2 files changed

+286
-31
lines changed

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export {
22
JsonSchema, AnyJsonSchema, ObjectJsonSchema, ArrayJsonSchema, IntegerJsonSchema, NumberJsonSchema, StringJsonSchema, BooleanJsonSchema, NullJsonSchema,
3+
isAnyJsonSchema, isObjectJsonSchema, isArrayJsonSchema, isIntegerJsonSchema, isNumberJsonSchema, isStringJsonSchema, isBooleanJsonSchema, isNullJsonSchema,
34
} from './jsonSchema';

src/jsonSchema.ts

Lines changed: 285 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,338 @@
1-
interface CommonJsonSchema<
2-
SchemaType,
3-
MappedTypeScriptType,
4-
LogicSubschema,
5-
> {
6-
allOf?: Array<LogicSubschema>,
7-
anyOf?: Array<LogicSubschema>,
8-
const?: MappedTypeScriptType,
9-
default?: MappedTypeScriptType,
1+
export interface NullJsonSchema {
2+
allOf?: Array<NullJsonSchema>,
3+
anyOf?: Array<NullJsonSchema>,
4+
const?: null,
5+
default?: null,
106
deprecated?: boolean,
117
description?: string,
12-
enum?: Array<MappedTypeScriptType>,
13-
examples?: Array<MappedTypeScriptType>,
14-
not?: LogicSubschema,
15-
oneOf?: Array<LogicSubschema>,
8+
enum?: Array<null>,
9+
examples?: Array<null>,
10+
not?: NullJsonSchema,
11+
oneOf?: Array<NullJsonSchema>,
1612
readOnly?: boolean,
1713
title?: string,
18-
type?: SchemaType,
14+
type?: 'null',
1915
writeOnly?: boolean
2016
}
2117

22-
export interface NullJsonSchema extends CommonJsonSchema<'null', null, NullJsonSchema> {
18+
export function isNullJsonSchema(schema: any): schema is NullJsonSchema {
19+
if (schema.type === 'null') {
20+
return true;
21+
}
22+
23+
if (Array.isArray(schema.type) && schema.type.includes('null')) {
24+
return true;
25+
}
26+
27+
return false;
2328
}
2429

25-
export interface BooleanJsonSchema extends CommonJsonSchema<'boolean', boolean, BooleanJsonSchema> {
30+
export interface BooleanJsonSchema {
31+
allOf?: Array<BooleanJsonSchema>,
32+
anyOf?: Array<BooleanJsonSchema>,
33+
const?: boolean,
34+
default?: boolean,
35+
deprecated?: boolean,
36+
description?: string,
37+
enum?: Array<boolean>,
38+
examples?: Array<boolean>,
39+
not?: BooleanJsonSchema,
40+
oneOf?: Array<BooleanJsonSchema>,
41+
readOnly?: boolean,
42+
title?: string,
43+
type?: 'boolean',
44+
writeOnly?: boolean
2645
}
2746

28-
export interface StringJsonSchema extends CommonJsonSchema<'string', string, StringJsonSchema> {
47+
export function isBooleanJsonSchema(schema: any): schema is BooleanJsonSchema {
48+
if (schema.type === 'boolean') {
49+
return true;
50+
}
51+
52+
if (Array.isArray(schema.type) && schema.type.includes('boolean')) {
53+
return true;
54+
}
55+
56+
return false;
57+
}
58+
59+
export interface StringJsonSchema {
60+
allOf?: Array<StringJsonSchema>,
61+
anyOf?: Array<StringJsonSchema>,
62+
const?: string,
63+
default?: string,
64+
deprecated?: string,
65+
description?: string,
66+
enum?: Array<string>,
67+
examples?: Array<string>,
2968
maxLength?: number,
3069
minLength?: number,
70+
not?: StringJsonSchema,
71+
oneOf?: Array<StringJsonSchema>,
3172
pattern?: string,
73+
readOnly?: boolean,
74+
title?: string,
75+
type?: 'string' | Array<'null' | 'boolean' | 'string' | 'integer' | 'number' | 'array' | 'object'>,
76+
writeOnly?: boolean
3277
}
3378

34-
export interface NumberJsonSchema extends CommonJsonSchema<'number', number, NumberJsonSchema> {
79+
export function isStringJsonSchema(schema: any): schema is StringJsonSchema {
80+
if (schema.type === 'string') {
81+
return true;
82+
}
83+
84+
if (Array.isArray(schema.type) && schema.type.includes('string')) {
85+
return true;
86+
}
87+
88+
if (schema.type === undefined && (
89+
schema.pattern !== undefined ||
90+
schema.minLength !== undefined ||
91+
schema.maxLength !== undefined
92+
)) {
93+
return true;
94+
}
95+
96+
return false;
97+
}
98+
99+
export interface NumberJsonSchema {
100+
allOf?: Array<NumberJsonSchema>,
101+
anyOf?: Array<NumberJsonSchema>,
102+
const?: number,
103+
default?: number,
104+
deprecated?: boolean,
105+
description?: string,
106+
enum?: Array<number>,
107+
examples?: Array<number>,
35108
exclusiveMaximum?: number,
36109
exclusiveMinimum?: number,
37110
maximum?: number,
38111
minimum?: number,
39112
multipleOf?: number,
113+
not?: NumberJsonSchema,
114+
oneOf?: Array<NumberJsonSchema>,
115+
readOnly?: boolean,
116+
title?: string,
117+
type?: 'number' | Array<'null' | 'boolean' | 'string' | 'integer' | 'number' | 'array' | 'object'>,
118+
writeOnly?: boolean
40119
}
41120

42-
export interface IntegerJsonSchema extends CommonJsonSchema<'integer', number, IntegerJsonSchema> {
121+
export function isNumberJsonSchema(schema: any): schema is NumberJsonSchema {
122+
if (schema.type === 'number') {
123+
return true;
124+
}
125+
126+
if (Array.isArray(schema.type) && schema.type.includes('number')) {
127+
return true;
128+
}
129+
130+
if (schema.type === undefined && (
131+
schema.multipleOf !== undefined ||
132+
schema.minimum !== undefined ||
133+
schema.maximum !== undefined ||
134+
schema.exclusiveMinimum !== undefined ||
135+
schema.exclusiveMaximum !== undefined
136+
)) {
137+
return true;
138+
}
139+
140+
return false;
141+
}
142+
143+
export interface IntegerJsonSchema {
144+
allOf?: Array<IntegerJsonSchema>,
145+
anyOf?: Array<IntegerJsonSchema>,
146+
const?: number,
147+
default?: number,
148+
deprecated?: boolean,
149+
description?: string,
150+
enum?: Array<number>,
151+
examples?: Array<number>,
43152
exclusiveMaximum?: number,
44153
exclusiveMinimum?: number,
45154
maximum?: number,
46155
minimum?: number,
47156
multipleOf?: number,
157+
not?: IntegerJsonSchema,
158+
oneOf?: Array<IntegerJsonSchema>,
159+
readOnly?: boolean,
160+
title?: string,
161+
type?: 'integer' | Array<'null' | 'boolean' | 'string' | 'integer' | 'number' | 'array' | 'object'>,
162+
writeOnly?: boolean
48163
}
49164

50-
export interface ArrayJsonSchema extends CommonJsonSchema<'array', Array<any>, ArrayJsonSchema> {
165+
export function isIntegerJsonSchema(schema: any): schema is IntegerJsonSchema {
166+
if (schema.type === 'integer') {
167+
return true;
168+
}
169+
170+
if (Array.isArray(schema.type) && schema.type.includes('integer')) {
171+
return true;
172+
}
173+
174+
if (schema.type === undefined && (
175+
schema.multipleOf !== undefined ||
176+
schema.minimum !== undefined ||
177+
schema.maximum !== undefined ||
178+
schema.exclusiveMinimum !== undefined ||
179+
schema.exclusiveMaximum !== undefined
180+
)) {
181+
return true;
182+
}
183+
184+
return false;
185+
}
186+
187+
export interface ArrayJsonSchema {
188+
allOf?: Array<ArrayJsonSchema>,
189+
anyOf?: Array<ArrayJsonSchema>,
190+
const?: Array<any>,
51191
contains?: JsonSchema,
192+
default?: Array<any>,
193+
deprecated?: boolean,
194+
description?: string,
195+
enum?: Array<Array<any>>,
196+
examples?: Array<Array<any>>,
52197
items?: JsonSchema,
53198
maxContains?: number,
54199
maxItems?: number,
55200
minContains?: number,
56201
minItems?: number,
202+
not?: ArrayJsonSchema,
203+
oneOf?: Array<ArrayJsonSchema>,
57204
prefixItems?: Array<JsonSchema>,
58-
uniqueItems?: boolean
205+
readOnly?: boolean,
206+
title?: string,
207+
type?: 'array' | Array<'null' | 'boolean' | 'string' | 'integer' | 'number' | 'array' | 'object'>,
208+
uniqueItems?: boolean,
209+
writeOnly?: boolean
210+
}
211+
212+
export function isArrayJsonSchema(schema: any): schema is ArrayJsonSchema {
213+
if (schema.type === 'array') {
214+
return true;
215+
}
216+
217+
if (Array.isArray(schema.type) && schema.type.includes('array')) {
218+
return true;
219+
}
220+
221+
if (schema.type === undefined && (
222+
schema.contains !== undefined ||
223+
schema.items !== undefined ||
224+
schema.maxContains !== undefined ||
225+
schema.maxItems !== undefined ||
226+
schema.minContains !== undefined ||
227+
schema.minItems !== undefined ||
228+
schema.prefixItems !== undefined ||
229+
schema.uniqueItems !== undefined
230+
)) {
231+
return true;
232+
}
233+
234+
return false;
59235
}
60236

61-
export interface ObjectJsonSchema extends CommonJsonSchema<'object', Record<string, any>, ObjectJsonSchema> {
237+
export interface ObjectJsonSchema {
62238
additionalProperties?: JsonSchema,
239+
allOf?: Array<ObjectJsonSchema>,
240+
anyOf?: Array<ObjectJsonSchema>,
241+
const?: Record<string, any>,
242+
default?: Record<string, any>,
63243
dependentRequired?: Record<string, Array<string>>,
244+
deprecated?: boolean,
245+
description?: string,
246+
enum?: Array<Record<string, any>>,
247+
examples?: Array<Record<string, any>>,
64248
maxProperties?: number,
65249
minProperties?: number,
250+
not?: ObjectJsonSchema,
251+
oneOf?: Array<ObjectJsonSchema>,
66252
patternProperties?: { [propertyNameRegex: string]: JsonSchema },
67253
properties?: { [propertyName: string]: JsonSchema },
68254
propertyNames?: JsonSchema,
255+
readOnly?: boolean,
69256
required?: Array<string>,
257+
title?: string,
258+
type?: 'object' | Array<'null' | 'boolean' | 'string' | 'integer' | 'number' | 'array' | 'object'>,
259+
writeOnly?: boolean
260+
}
261+
262+
export function isObjectJsonSchema(schema: any): schema is ObjectJsonSchema {
263+
if (schema.type === 'object') {
264+
return true;
265+
}
266+
267+
if (Array.isArray(schema.type) && schema.type.includes('object')) {
268+
return true;
269+
}
270+
271+
if (schema.type === undefined && (
272+
schema.additionalProperties !== undefined ||
273+
schema.dependentRequired !== undefined ||
274+
schema.maxProperties !== undefined ||
275+
schema.minProperties !== undefined ||
276+
schema.patternProperties !== undefined ||
277+
schema.properties !== undefined ||
278+
schema.propertyNames !== undefined ||
279+
schema.required !== undefined
280+
)) {
281+
return true;
282+
}
283+
284+
return false;
70285
}
71286

72-
type CommonProperties = keyof CommonJsonSchema<any, any, any>;
287+
export interface AnyJsonSchema {
288+
additionalProperties?: never,
289+
allOf?: never,
290+
anyOf?: never,
291+
const?: any,
292+
contains?: never,
293+
default?: any,
294+
dependentRequired?: never,
295+
deprecated?: boolean,
296+
description?: string,
297+
enum?: Array<any>,
298+
examples?: Array<any>,
299+
exclusiveMaximum?: never,
300+
exclusiveMinimum?: never,
301+
items?: never,
302+
maxContains?: never,
303+
maxItems?: never,
304+
maxLength?: never,
305+
maxProperties?: never,
306+
maximum?: never,
307+
minContains?: never,
308+
minItems?: never,
309+
minLength?: never,
310+
minProperties?: never,
311+
minimum?: never,
312+
multipleOf?: never,
313+
not?: never,
314+
oneOf?: never,
315+
pattern?: never,
316+
patternProperties?: never,
317+
prefixItems?: never,
318+
properties?: never,
319+
propertyNames?: never,
320+
readOnly?: boolean,
321+
required?: never,
322+
title?: string,
323+
type?: never,
324+
uniqueItems?: never,
325+
writeOnly?: boolean
326+
}
73327

74-
export interface AnyJsonSchema extends Omit<NullJsonSchema, CommonProperties>,
75-
Omit<BooleanJsonSchema, CommonProperties>,
76-
Omit<StringJsonSchema, CommonProperties>,
77-
Omit<NumberJsonSchema, CommonProperties>,
78-
Omit<IntegerJsonSchema, CommonProperties>,
79-
Omit<ArrayJsonSchema, CommonProperties>,
80-
Omit<ObjectJsonSchema, CommonProperties>,
81-
CommonJsonSchema<undefined | Array<'string' | 'integer' | 'number' | 'array' | 'object' | 'boolean' | 'null'>, any, JsonSchema> {
328+
export function isAnyJsonSchema(schema: any): schema is AnyJsonSchema {
329+
return !isNullJsonSchema(schema)
330+
&& !isBooleanJsonSchema(schema)
331+
&& !isStringJsonSchema(schema)
332+
&& !isNumberJsonSchema(schema)
333+
&& !isIntegerJsonSchema(schema)
334+
&& !isArrayJsonSchema(schema)
335+
&& !isObjectJsonSchema(schema);
82336
}
83337

84338
export type JsonSchema = NullJsonSchema | BooleanJsonSchema | StringJsonSchema | NumberJsonSchema | IntegerJsonSchema | ArrayJsonSchema | ObjectJsonSchema | AnyJsonSchema;

0 commit comments

Comments
 (0)