@naturalcycles/js-lib 15.46.0 → 15.47.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/http/fetcher.d.ts +1 -1
- package/dist/http/fetcher.js +1 -1
- package/dist/promise/pProps.js +1 -1
- package/dist/promise/pTimeout.js +1 -1
- package/dist/semver.js +1 -0
- package/dist/web.d.ts +1 -1
- package/dist/web.js +1 -1
- package/package.json +3 -4
- package/readme.md +0 -8
- package/src/http/fetcher.ts +1 -1
- package/src/promise/pProps.ts +1 -1
- package/src/promise/pTimeout.ts +1 -1
- package/src/semver.ts +1 -0
- package/src/types.ts +4 -4
- package/src/web.ts +1 -1
- package/src/zod/zod.shared.schemas.ts +1 -1
- package/dist/json-schema/from-data/generateJsonSchemaFromData.d.ts +0 -8
- package/dist/json-schema/from-data/generateJsonSchemaFromData.js +0 -87
- package/dist/json-schema/index.d.ts +0 -5
- package/dist/json-schema/index.js +0 -5
- package/dist/json-schema/jsonSchema.cnst.d.ts +0 -2
- package/dist/json-schema/jsonSchema.cnst.js +0 -38
- package/dist/json-schema/jsonSchema.model.d.ts +0 -121
- package/dist/json-schema/jsonSchema.model.js +0 -1
- package/dist/json-schema/jsonSchema.util.d.ts +0 -8
- package/dist/json-schema/jsonSchema.util.js +0 -27
- package/dist/json-schema/jsonSchemaBuilder.d.ts +0 -159
- package/dist/json-schema/jsonSchemaBuilder.js +0 -412
- package/dist/json-schema/jsonSchemas.d.ts +0 -2
- package/dist/json-schema/jsonSchemas.js +0 -6
- package/src/json-schema/from-data/generateJsonSchemaFromData.ts +0 -121
- package/src/json-schema/index.ts +0 -5
- package/src/json-schema/jsonSchema.cnst.ts +0 -52
- package/src/json-schema/jsonSchema.model.ts +0 -172
- package/src/json-schema/jsonSchema.util.ts +0 -36
- package/src/json-schema/jsonSchemaBuilder.ts +0 -590
- package/src/json-schema/jsonSchemas.ts +0 -8
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
import { type AnyObject, type BaseDBEntity, type IsoDate, type IsoDateTime, type NumberEnum, type StringEnum, type UnixTimestamp, type UnixTimestampMillis } from '../types.js';
|
|
2
|
-
import type { JsonSchema, JsonSchemaAllOf, JsonSchemaAny, JsonSchemaArray, JsonSchemaBoolean, JsonSchemaConst, JsonSchemaEnum, JsonSchemaNull, JsonSchemaNumber, JsonSchemaObject, JsonSchemaOneOf, JsonSchemaRef, JsonSchemaString, JsonSchemaTuple } from './jsonSchema.model.js';
|
|
3
|
-
export interface JsonSchemaBuilder<T = unknown> {
|
|
4
|
-
build: () => JsonSchema<T>;
|
|
5
|
-
}
|
|
6
|
-
/**
|
|
7
|
-
* Fluent (chainable) API to manually create Json Schemas.
|
|
8
|
-
* Inspired by Joi and Zod.
|
|
9
|
-
*/
|
|
10
|
-
export declare const j: {
|
|
11
|
-
any<T = unknown>(): JsonSchemaAnyBuilder<T, JsonSchemaAny<T>, false>;
|
|
12
|
-
const<T extends string | number | boolean | null>(value: T): JsonSchemaAnyBuilder<T, JsonSchemaConst<T>, false>;
|
|
13
|
-
null(): JsonSchemaAnyBuilder<null, JsonSchemaNull, false>;
|
|
14
|
-
ref<T = unknown>($ref: string): JsonSchemaAnyBuilder<T, JsonSchemaRef<T>, false>;
|
|
15
|
-
enum<const T extends readonly (string | number | boolean | null)[] | StringEnum | NumberEnum>(input: T): JsonSchemaAnyBuilder<T extends readonly (infer U)[] ? U : T extends StringEnum ? T[keyof T] : T extends NumberEnum ? T[keyof T] : never, JsonSchemaEnum<any>, false>;
|
|
16
|
-
boolean(): JsonSchemaAnyBuilder<boolean, JsonSchemaBoolean, false>;
|
|
17
|
-
buffer(): JsonSchemaAnyBuilder<Buffer<ArrayBufferLike>, JsonSchemaAny<Buffer<ArrayBufferLike>>, false>;
|
|
18
|
-
number<T extends number = number>(): JsonSchemaNumberBuilder<T, false>;
|
|
19
|
-
integer<T extends number = number>(): JsonSchemaNumberBuilder<T, false>;
|
|
20
|
-
string<T extends string = string>(): JsonSchemaStringBuilder<T, false>;
|
|
21
|
-
object: typeof object;
|
|
22
|
-
dbEntity<P extends Record<string, JsonSchemaAnyBuilder<any, any, any>>>(props: P): JsonSchemaObjectBuilder<BaseDBEntity & { [K in keyof P]: P[K] extends JsonSchemaAnyBuilder<infer U, any, any> ? U : never; }>;
|
|
23
|
-
rootObject<T extends AnyObject>(props: { [K in keyof T]: JsonSchemaAnyBuilder<T[K]>; }): JsonSchemaObjectBuilder<T, false>;
|
|
24
|
-
array<T extends JsonSchemaAnyBuilder<any>>(itemSchema: T): JsonSchemaArrayBuilder<T["infer"], false>;
|
|
25
|
-
tuple<T extends any[] = unknown[]>(items: JsonSchemaAnyBuilder[]): JsonSchemaTupleBuilder<T>;
|
|
26
|
-
oneOf<Builders extends JsonSchemaAnyBuilder<any, any, any>[]>(items: [...Builders]): JsonSchemaAnyBuilder<Builders[number] extends JsonSchemaAnyBuilder<infer U, any, any> ? U : never, JsonSchemaOneOf<Builders[number] extends JsonSchemaAnyBuilder<infer U, any, any> ? U : never>>;
|
|
27
|
-
allOf<T = unknown>(items: JsonSchemaAnyBuilder[]): JsonSchemaAnyBuilder<T, JsonSchemaAllOf<T>, false>;
|
|
28
|
-
};
|
|
29
|
-
export declare class JsonSchemaAnyBuilder<T = unknown, SCHEMA_TYPE extends JsonSchema<T> = JsonSchema<T>, Opt extends boolean = false> implements JsonSchemaBuilder<T> {
|
|
30
|
-
protected schema: SCHEMA_TYPE;
|
|
31
|
-
constructor(schema: SCHEMA_TYPE);
|
|
32
|
-
/**
|
|
33
|
-
* Used in ObjectBuilder to access schema.optionalProperty
|
|
34
|
-
*/
|
|
35
|
-
getSchema(): SCHEMA_TYPE;
|
|
36
|
-
$schema($schema: string): this;
|
|
37
|
-
$schemaDraft7(): this;
|
|
38
|
-
$id($id: string): this;
|
|
39
|
-
title(title: string): this;
|
|
40
|
-
description(description: string): this;
|
|
41
|
-
deprecated(deprecated?: boolean): this;
|
|
42
|
-
type(type: string): this;
|
|
43
|
-
default(v: any): this;
|
|
44
|
-
instanceof(of: string): this;
|
|
45
|
-
optional(): JsonSchemaAnyBuilder<T | undefined, JsonSchema<T | undefined>, true>;
|
|
46
|
-
optional(optional: true): JsonSchemaAnyBuilder<T | undefined, JsonSchema<T | undefined>, true>;
|
|
47
|
-
optional(optional: false): JsonSchemaAnyBuilder<Exclude<T, undefined>, JsonSchema<Exclude<T, undefined>>, false>;
|
|
48
|
-
nullable(): JsonSchemaAnyBuilder<T | null, JsonSchema<T | null>, Opt>;
|
|
49
|
-
/**
|
|
50
|
-
* Produces a "clean schema object" without methods.
|
|
51
|
-
* Same as if it would be JSON.stringified.
|
|
52
|
-
*/
|
|
53
|
-
build(): SCHEMA_TYPE;
|
|
54
|
-
clone(): JsonSchemaAnyBuilder<T, SCHEMA_TYPE, Opt>;
|
|
55
|
-
/**
|
|
56
|
-
* @experimental
|
|
57
|
-
*/
|
|
58
|
-
infer: T;
|
|
59
|
-
}
|
|
60
|
-
export declare class JsonSchemaNumberBuilder<T extends number = number, Opt extends boolean = false> extends JsonSchemaAnyBuilder<T, JsonSchemaNumber<T>, Opt> {
|
|
61
|
-
constructor();
|
|
62
|
-
integer(): this;
|
|
63
|
-
multipleOf(multipleOf: number): this;
|
|
64
|
-
min(minimum: number): this;
|
|
65
|
-
exclusiveMin(exclusiveMinimum: number): this;
|
|
66
|
-
max(maximum: number): this;
|
|
67
|
-
exclusiveMax(exclusiveMaximum: number): this;
|
|
68
|
-
/**
|
|
69
|
-
* Both ranges are inclusive.
|
|
70
|
-
*/
|
|
71
|
-
range(minimum: number, maximum: number): this;
|
|
72
|
-
format(format: string): this;
|
|
73
|
-
int32: () => this;
|
|
74
|
-
int64: () => this;
|
|
75
|
-
float: () => this;
|
|
76
|
-
double: () => this;
|
|
77
|
-
unixTimestamp: () => JsonSchemaNumberBuilder<UnixTimestamp>;
|
|
78
|
-
unixTimestamp2000: () => JsonSchemaNumberBuilder<UnixTimestamp>;
|
|
79
|
-
unixTimestampMillis: () => JsonSchemaNumberBuilder<UnixTimestampMillis>;
|
|
80
|
-
unixTimestampMillis2000: () => JsonSchemaNumberBuilder<UnixTimestampMillis>;
|
|
81
|
-
utcOffset: () => this;
|
|
82
|
-
utcOffsetHours: () => this;
|
|
83
|
-
branded<B extends number>(): JsonSchemaNumberBuilder<B>;
|
|
84
|
-
}
|
|
85
|
-
export declare class JsonSchemaStringBuilder<T extends string = string, Opt extends boolean = false> extends JsonSchemaAnyBuilder<T, JsonSchemaString<T>, Opt> {
|
|
86
|
-
constructor();
|
|
87
|
-
regex(pattern: RegExp): this;
|
|
88
|
-
pattern(pattern: string): this;
|
|
89
|
-
min(minLength: number): this;
|
|
90
|
-
max(maxLength: number): this;
|
|
91
|
-
length(minLength: number, maxLength: number): this;
|
|
92
|
-
format(format: string): this;
|
|
93
|
-
email: () => this;
|
|
94
|
-
url: () => this;
|
|
95
|
-
ipv4: () => this;
|
|
96
|
-
ipv6: () => this;
|
|
97
|
-
password: () => this;
|
|
98
|
-
id: () => this;
|
|
99
|
-
slug: () => this;
|
|
100
|
-
semVer: () => this;
|
|
101
|
-
languageTag: () => this;
|
|
102
|
-
countryCode: () => this;
|
|
103
|
-
currency: () => this;
|
|
104
|
-
trim(trim?: boolean): this;
|
|
105
|
-
toLowerCase(toLowerCase?: boolean): this;
|
|
106
|
-
toUpperCase(toUpperCase?: boolean): this;
|
|
107
|
-
truncate(toLength: number): this;
|
|
108
|
-
branded<B extends string>(): JsonSchemaStringBuilder<B>;
|
|
109
|
-
/**
|
|
110
|
-
* Accepts only the `YYYY-MM-DD` shape from all ISO 8601 variants.
|
|
111
|
-
*/
|
|
112
|
-
isoDate(): JsonSchemaStringBuilder<IsoDate>;
|
|
113
|
-
/**
|
|
114
|
-
* Accepts strings that start with the `YYYY-MM-DDTHH:MM:SS` shape
|
|
115
|
-
* and optionally end with either a `Z` or a `+/-hh:mm` timezone part.
|
|
116
|
-
*/
|
|
117
|
-
isoDateTime(): JsonSchemaStringBuilder<IsoDateTime>;
|
|
118
|
-
jwt(): this;
|
|
119
|
-
}
|
|
120
|
-
export declare class JsonSchemaObjectBuilder<T extends AnyObject, Opt extends boolean = false> extends JsonSchemaAnyBuilder<T, JsonSchemaObject<T>, Opt> {
|
|
121
|
-
constructor();
|
|
122
|
-
addProperties(props?: {
|
|
123
|
-
[k in keyof T]: JsonSchemaBuilder<T[k]>;
|
|
124
|
-
}): this;
|
|
125
|
-
/**
|
|
126
|
-
* Ensures `required` is always sorted and _uniq
|
|
127
|
-
*/
|
|
128
|
-
required(required: (keyof T)[]): this;
|
|
129
|
-
addRequired(required: (keyof T)[]): this;
|
|
130
|
-
minProps(minProperties: number): this;
|
|
131
|
-
maxProps(maxProperties: number): this;
|
|
132
|
-
additionalProps(additionalProperties: boolean): this;
|
|
133
|
-
baseDBEntity(): JsonSchemaObjectBuilder<T & BaseDBEntity>;
|
|
134
|
-
extend<T2 extends AnyObject>(s2: JsonSchemaObjectBuilder<T2>): JsonSchemaObjectBuilder<T & T2 extends infer O ? {
|
|
135
|
-
[K in keyof O]: O[K];
|
|
136
|
-
} : never>;
|
|
137
|
-
}
|
|
138
|
-
export declare class JsonSchemaArrayBuilder<ITEM, Opt extends boolean = false> extends JsonSchemaAnyBuilder<ITEM[], JsonSchemaArray<ITEM>, Opt> {
|
|
139
|
-
constructor(itemsSchema: JsonSchemaBuilder<ITEM>);
|
|
140
|
-
min(minItems: number): this;
|
|
141
|
-
max(maxItems: number): this;
|
|
142
|
-
unique(uniqueItems?: boolean): this;
|
|
143
|
-
}
|
|
144
|
-
export declare class JsonSchemaTupleBuilder<T extends any[]> extends JsonSchemaAnyBuilder<T, JsonSchemaTuple<T>> {
|
|
145
|
-
constructor(items: JsonSchemaBuilder[]);
|
|
146
|
-
}
|
|
147
|
-
declare function object<P extends Record<string, JsonSchemaAnyBuilder<any, any, any>>>(props?: {
|
|
148
|
-
[K in keyof P]: P[K] & JsonSchemaAnyBuilder<any, any, any>;
|
|
149
|
-
}): JsonSchemaObjectBuilder<{
|
|
150
|
-
[K in keyof P as P[K] extends JsonSchemaAnyBuilder<any, any, infer Opt> ? Opt extends true ? never : K : never]: P[K] extends JsonSchemaAnyBuilder<infer U, any, any> ? U : never;
|
|
151
|
-
} & {
|
|
152
|
-
[K in keyof P as P[K] extends JsonSchemaAnyBuilder<any, any, infer Opt> ? Opt extends true ? K : never : never]?: P[K] extends JsonSchemaAnyBuilder<infer U, any, any> ? U : never;
|
|
153
|
-
} extends infer O ? {
|
|
154
|
-
[K in keyof O]: O[K];
|
|
155
|
-
} : never>;
|
|
156
|
-
declare function object<T extends AnyObject>(props?: {
|
|
157
|
-
[K in keyof T]: JsonSchemaAnyBuilder<T[K]>;
|
|
158
|
-
}): JsonSchemaObjectBuilder<T>;
|
|
159
|
-
export {};
|
|
@@ -1,412 +0,0 @@
|
|
|
1
|
-
import { _uniq } from '../array/array.util.js';
|
|
2
|
-
import { _numberEnumValues, _stringEnumValues, getEnumType } from '../enum.util.js';
|
|
3
|
-
import { _assert } from '../error/assert.js';
|
|
4
|
-
import { _deepCopy } from '../object/object.util.js';
|
|
5
|
-
import { _sortObject } from '../object/sortObject.js';
|
|
6
|
-
import { JWT_REGEX, } from '../types.js';
|
|
7
|
-
import { JSON_SCHEMA_ORDER } from './jsonSchema.cnst.js';
|
|
8
|
-
import { mergeJsonSchemaObjects } from './jsonSchema.util.js';
|
|
9
|
-
/**
|
|
10
|
-
* Fluent (chainable) API to manually create Json Schemas.
|
|
11
|
-
* Inspired by Joi and Zod.
|
|
12
|
-
*/
|
|
13
|
-
export const j = {
|
|
14
|
-
any() {
|
|
15
|
-
return new JsonSchemaAnyBuilder({});
|
|
16
|
-
},
|
|
17
|
-
const(value) {
|
|
18
|
-
return new JsonSchemaAnyBuilder({
|
|
19
|
-
const: value,
|
|
20
|
-
});
|
|
21
|
-
},
|
|
22
|
-
null() {
|
|
23
|
-
return new JsonSchemaAnyBuilder({
|
|
24
|
-
type: 'null',
|
|
25
|
-
});
|
|
26
|
-
},
|
|
27
|
-
ref($ref) {
|
|
28
|
-
return new JsonSchemaAnyBuilder({
|
|
29
|
-
$ref,
|
|
30
|
-
});
|
|
31
|
-
},
|
|
32
|
-
enum(input) {
|
|
33
|
-
let enumValues;
|
|
34
|
-
if (Array.isArray(input)) {
|
|
35
|
-
enumValues = input;
|
|
36
|
-
}
|
|
37
|
-
else if (typeof input === 'object') {
|
|
38
|
-
const enumType = getEnumType(input);
|
|
39
|
-
if (enumType === 'NumberEnum') {
|
|
40
|
-
enumValues = _numberEnumValues(input);
|
|
41
|
-
}
|
|
42
|
-
else if (enumType === 'StringEnum') {
|
|
43
|
-
enumValues = _stringEnumValues(input);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
_assert(enumValues, 'Unsupported enum input');
|
|
47
|
-
return new JsonSchemaAnyBuilder({
|
|
48
|
-
enum: enumValues,
|
|
49
|
-
});
|
|
50
|
-
},
|
|
51
|
-
boolean() {
|
|
52
|
-
return new JsonSchemaAnyBuilder({
|
|
53
|
-
type: 'boolean',
|
|
54
|
-
});
|
|
55
|
-
},
|
|
56
|
-
buffer() {
|
|
57
|
-
return new JsonSchemaAnyBuilder({ instanceof: 'Buffer' });
|
|
58
|
-
},
|
|
59
|
-
// number types
|
|
60
|
-
number() {
|
|
61
|
-
return new JsonSchemaNumberBuilder();
|
|
62
|
-
},
|
|
63
|
-
integer() {
|
|
64
|
-
return new JsonSchemaNumberBuilder().integer();
|
|
65
|
-
},
|
|
66
|
-
// string types
|
|
67
|
-
string() {
|
|
68
|
-
return new JsonSchemaStringBuilder();
|
|
69
|
-
},
|
|
70
|
-
// complex types
|
|
71
|
-
object,
|
|
72
|
-
dbEntity(props) {
|
|
73
|
-
return j
|
|
74
|
-
.object({
|
|
75
|
-
id: j.string(),
|
|
76
|
-
created: j.integer().unixTimestamp2000(),
|
|
77
|
-
updated: j.integer().unixTimestamp2000(),
|
|
78
|
-
})
|
|
79
|
-
.extend(j.object(props));
|
|
80
|
-
},
|
|
81
|
-
rootObject(props) {
|
|
82
|
-
return new JsonSchemaObjectBuilder().addProperties(props).$schemaDraft7();
|
|
83
|
-
},
|
|
84
|
-
array(itemSchema) {
|
|
85
|
-
return new JsonSchemaArrayBuilder(itemSchema);
|
|
86
|
-
},
|
|
87
|
-
tuple(items) {
|
|
88
|
-
return new JsonSchemaTupleBuilder(items);
|
|
89
|
-
},
|
|
90
|
-
oneOf(items) {
|
|
91
|
-
return new JsonSchemaAnyBuilder({
|
|
92
|
-
oneOf: items.map(b => b.build()),
|
|
93
|
-
});
|
|
94
|
-
},
|
|
95
|
-
allOf(items) {
|
|
96
|
-
return new JsonSchemaAnyBuilder({
|
|
97
|
-
allOf: items.map(b => b.build()),
|
|
98
|
-
});
|
|
99
|
-
},
|
|
100
|
-
};
|
|
101
|
-
export class JsonSchemaAnyBuilder {
|
|
102
|
-
schema;
|
|
103
|
-
constructor(schema) {
|
|
104
|
-
this.schema = schema;
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* Used in ObjectBuilder to access schema.optionalProperty
|
|
108
|
-
*/
|
|
109
|
-
getSchema() {
|
|
110
|
-
return this.schema;
|
|
111
|
-
}
|
|
112
|
-
$schema($schema) {
|
|
113
|
-
Object.assign(this.schema, { $schema });
|
|
114
|
-
return this;
|
|
115
|
-
}
|
|
116
|
-
$schemaDraft7() {
|
|
117
|
-
this.$schema('http://json-schema.org/draft-07/schema#');
|
|
118
|
-
return this;
|
|
119
|
-
}
|
|
120
|
-
$id($id) {
|
|
121
|
-
Object.assign(this.schema, { $id });
|
|
122
|
-
return this;
|
|
123
|
-
}
|
|
124
|
-
title(title) {
|
|
125
|
-
Object.assign(this.schema, { title });
|
|
126
|
-
return this;
|
|
127
|
-
}
|
|
128
|
-
description(description) {
|
|
129
|
-
Object.assign(this.schema, { description });
|
|
130
|
-
return this;
|
|
131
|
-
}
|
|
132
|
-
deprecated(deprecated = true) {
|
|
133
|
-
Object.assign(this.schema, { deprecated });
|
|
134
|
-
return this;
|
|
135
|
-
}
|
|
136
|
-
type(type) {
|
|
137
|
-
Object.assign(this.schema, { type });
|
|
138
|
-
return this;
|
|
139
|
-
}
|
|
140
|
-
default(v) {
|
|
141
|
-
Object.assign(this.schema, { default: v });
|
|
142
|
-
return this;
|
|
143
|
-
}
|
|
144
|
-
instanceof(of) {
|
|
145
|
-
Object.assign(this.schema, { type: 'object', instanceof: of });
|
|
146
|
-
return this;
|
|
147
|
-
}
|
|
148
|
-
optional(optional = true) {
|
|
149
|
-
if (optional) {
|
|
150
|
-
this.schema.optionalField = true;
|
|
151
|
-
}
|
|
152
|
-
else {
|
|
153
|
-
this.schema.optionalField = undefined;
|
|
154
|
-
}
|
|
155
|
-
return this;
|
|
156
|
-
}
|
|
157
|
-
nullable() {
|
|
158
|
-
return new JsonSchemaAnyBuilder({
|
|
159
|
-
anyOf: [this.build(), { type: 'null' }],
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
/**
|
|
163
|
-
* Produces a "clean schema object" without methods.
|
|
164
|
-
* Same as if it would be JSON.stringified.
|
|
165
|
-
*/
|
|
166
|
-
build() {
|
|
167
|
-
return _sortObject(JSON.parse(JSON.stringify(this.schema)), JSON_SCHEMA_ORDER);
|
|
168
|
-
}
|
|
169
|
-
clone() {
|
|
170
|
-
return new JsonSchemaAnyBuilder(_deepCopy(this.schema));
|
|
171
|
-
}
|
|
172
|
-
/**
|
|
173
|
-
* @experimental
|
|
174
|
-
*/
|
|
175
|
-
infer;
|
|
176
|
-
}
|
|
177
|
-
export class JsonSchemaNumberBuilder extends JsonSchemaAnyBuilder {
|
|
178
|
-
constructor() {
|
|
179
|
-
super({
|
|
180
|
-
type: 'number',
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
integer() {
|
|
184
|
-
Object.assign(this.schema, { type: 'integer' });
|
|
185
|
-
return this;
|
|
186
|
-
}
|
|
187
|
-
multipleOf(multipleOf) {
|
|
188
|
-
Object.assign(this.schema, { multipleOf });
|
|
189
|
-
return this;
|
|
190
|
-
}
|
|
191
|
-
min(minimum) {
|
|
192
|
-
Object.assign(this.schema, { minimum });
|
|
193
|
-
return this;
|
|
194
|
-
}
|
|
195
|
-
exclusiveMin(exclusiveMinimum) {
|
|
196
|
-
Object.assign(this.schema, { exclusiveMinimum });
|
|
197
|
-
return this;
|
|
198
|
-
}
|
|
199
|
-
max(maximum) {
|
|
200
|
-
Object.assign(this.schema, { maximum });
|
|
201
|
-
return this;
|
|
202
|
-
}
|
|
203
|
-
exclusiveMax(exclusiveMaximum) {
|
|
204
|
-
Object.assign(this.schema, { exclusiveMaximum });
|
|
205
|
-
return this;
|
|
206
|
-
}
|
|
207
|
-
/**
|
|
208
|
-
* Both ranges are inclusive.
|
|
209
|
-
*/
|
|
210
|
-
range(minimum, maximum) {
|
|
211
|
-
Object.assign(this.schema, { minimum, maximum });
|
|
212
|
-
return this;
|
|
213
|
-
}
|
|
214
|
-
format(format) {
|
|
215
|
-
Object.assign(this.schema, { format });
|
|
216
|
-
return this;
|
|
217
|
-
}
|
|
218
|
-
int32 = () => this.format('int32');
|
|
219
|
-
int64 = () => this.format('int64');
|
|
220
|
-
float = () => this.format('float');
|
|
221
|
-
double = () => this.format('double');
|
|
222
|
-
unixTimestamp = () => this.integer().branded().format('unixTimestamp').description('UnixTimestamp');
|
|
223
|
-
unixTimestamp2000 = () => this.integer()
|
|
224
|
-
.branded()
|
|
225
|
-
.format('unixTimestamp2000')
|
|
226
|
-
.description('UnixTimestamp2000');
|
|
227
|
-
unixTimestampMillis = () => this.integer()
|
|
228
|
-
.branded()
|
|
229
|
-
.format('unixTimestampMillis')
|
|
230
|
-
.description('UnixTimestampMillis');
|
|
231
|
-
unixTimestampMillis2000 = () => this.integer()
|
|
232
|
-
.branded()
|
|
233
|
-
.format('unixTimestampMillis2000')
|
|
234
|
-
.description('UnixTimestampMillis2000');
|
|
235
|
-
utcOffset = () => this.format('utcOffset');
|
|
236
|
-
utcOffsetHours = () => this.format('utcOffsetHours');
|
|
237
|
-
branded() {
|
|
238
|
-
return this;
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
export class JsonSchemaStringBuilder extends JsonSchemaAnyBuilder {
|
|
242
|
-
constructor() {
|
|
243
|
-
super({
|
|
244
|
-
type: 'string',
|
|
245
|
-
});
|
|
246
|
-
}
|
|
247
|
-
regex(pattern) {
|
|
248
|
-
return this.pattern(pattern.source);
|
|
249
|
-
}
|
|
250
|
-
pattern(pattern) {
|
|
251
|
-
Object.assign(this.schema, { pattern });
|
|
252
|
-
return this;
|
|
253
|
-
}
|
|
254
|
-
min(minLength) {
|
|
255
|
-
Object.assign(this.schema, { minLength });
|
|
256
|
-
return this;
|
|
257
|
-
}
|
|
258
|
-
max(maxLength) {
|
|
259
|
-
Object.assign(this.schema, { maxLength });
|
|
260
|
-
return this;
|
|
261
|
-
}
|
|
262
|
-
length(minLength, maxLength) {
|
|
263
|
-
Object.assign(this.schema, { minLength, maxLength });
|
|
264
|
-
return this;
|
|
265
|
-
}
|
|
266
|
-
format(format) {
|
|
267
|
-
Object.assign(this.schema, { format });
|
|
268
|
-
return this;
|
|
269
|
-
}
|
|
270
|
-
email = () => this.format('email');
|
|
271
|
-
url = () => this.format('url');
|
|
272
|
-
ipv4 = () => this.format('ipv4');
|
|
273
|
-
ipv6 = () => this.format('ipv6');
|
|
274
|
-
password = () => this.format('password');
|
|
275
|
-
id = () => this.format('id');
|
|
276
|
-
slug = () => this.format('slug');
|
|
277
|
-
semVer = () => this.format('semVer');
|
|
278
|
-
languageTag = () => this.format('languageTag');
|
|
279
|
-
countryCode = () => this.format('countryCode');
|
|
280
|
-
currency = () => this.format('currency');
|
|
281
|
-
trim(trim = true) {
|
|
282
|
-
Object.assign(this.schema, { transform: { ...this.schema.transform, trim } });
|
|
283
|
-
return this;
|
|
284
|
-
}
|
|
285
|
-
toLowerCase(toLowerCase = true) {
|
|
286
|
-
Object.assign(this.schema, { transform: { ...this.schema.transform, toLowerCase } });
|
|
287
|
-
return this;
|
|
288
|
-
}
|
|
289
|
-
toUpperCase(toUpperCase = true) {
|
|
290
|
-
Object.assign(this.schema, { transform: { ...this.schema.transform, toUpperCase } });
|
|
291
|
-
return this;
|
|
292
|
-
}
|
|
293
|
-
truncate(toLength) {
|
|
294
|
-
Object.assign(this.schema, { transform: { ...this.schema.transform, truncate: toLength } });
|
|
295
|
-
return this;
|
|
296
|
-
}
|
|
297
|
-
branded() {
|
|
298
|
-
return this;
|
|
299
|
-
}
|
|
300
|
-
/**
|
|
301
|
-
* Accepts only the `YYYY-MM-DD` shape from all ISO 8601 variants.
|
|
302
|
-
*/
|
|
303
|
-
isoDate() {
|
|
304
|
-
return this.format('IsoDate').branded().description('IsoDate');
|
|
305
|
-
}
|
|
306
|
-
/**
|
|
307
|
-
* Accepts strings that start with the `YYYY-MM-DDTHH:MM:SS` shape
|
|
308
|
-
* and optionally end with either a `Z` or a `+/-hh:mm` timezone part.
|
|
309
|
-
*/
|
|
310
|
-
isoDateTime() {
|
|
311
|
-
return this.format('IsoDateTime').branded().description('IsoDateTime');
|
|
312
|
-
}
|
|
313
|
-
jwt() {
|
|
314
|
-
return this.regex(JWT_REGEX);
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
export class JsonSchemaObjectBuilder extends JsonSchemaAnyBuilder {
|
|
318
|
-
constructor() {
|
|
319
|
-
super({
|
|
320
|
-
type: 'object',
|
|
321
|
-
properties: {},
|
|
322
|
-
required: [],
|
|
323
|
-
additionalProperties: false,
|
|
324
|
-
});
|
|
325
|
-
}
|
|
326
|
-
addProperties(props) {
|
|
327
|
-
if (!props)
|
|
328
|
-
return this;
|
|
329
|
-
Object.entries(props).forEach(([k, builder]) => {
|
|
330
|
-
const schema = builder.build();
|
|
331
|
-
if (!schema.optionalField) {
|
|
332
|
-
this.schema.required.push(k);
|
|
333
|
-
}
|
|
334
|
-
else {
|
|
335
|
-
schema.optionalField = undefined;
|
|
336
|
-
}
|
|
337
|
-
this.schema.properties[k] = schema;
|
|
338
|
-
});
|
|
339
|
-
this.required(this.schema.required); // ensure it's sorted and _uniq
|
|
340
|
-
return this;
|
|
341
|
-
}
|
|
342
|
-
/**
|
|
343
|
-
* Ensures `required` is always sorted and _uniq
|
|
344
|
-
*/
|
|
345
|
-
required(required) {
|
|
346
|
-
Object.assign(this.schema, { required });
|
|
347
|
-
this.schema.required = _uniq(required).sort();
|
|
348
|
-
return this;
|
|
349
|
-
}
|
|
350
|
-
addRequired(required) {
|
|
351
|
-
return this.required([...this.schema.required, ...required]);
|
|
352
|
-
}
|
|
353
|
-
minProps(minProperties) {
|
|
354
|
-
Object.assign(this.schema, { minProperties });
|
|
355
|
-
return this;
|
|
356
|
-
}
|
|
357
|
-
maxProps(maxProperties) {
|
|
358
|
-
Object.assign(this.schema, { maxProperties });
|
|
359
|
-
return this;
|
|
360
|
-
}
|
|
361
|
-
additionalProps(additionalProperties) {
|
|
362
|
-
Object.assign(this.schema, { additionalProperties });
|
|
363
|
-
return this;
|
|
364
|
-
}
|
|
365
|
-
baseDBEntity() {
|
|
366
|
-
Object.assign(this.schema.properties, {
|
|
367
|
-
id: { type: 'string' },
|
|
368
|
-
created: { type: 'number', format: 'unixTimestamp2000' },
|
|
369
|
-
updated: { type: 'number', format: 'unixTimestamp2000' },
|
|
370
|
-
});
|
|
371
|
-
return this.addRequired(['id', 'created', 'updated']);
|
|
372
|
-
}
|
|
373
|
-
extend(s2) {
|
|
374
|
-
const builder = new JsonSchemaObjectBuilder();
|
|
375
|
-
Object.assign(builder.schema, _deepCopy(this.schema));
|
|
376
|
-
mergeJsonSchemaObjects(builder.schema, s2.schema);
|
|
377
|
-
return builder;
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
export class JsonSchemaArrayBuilder extends JsonSchemaAnyBuilder {
|
|
381
|
-
constructor(itemsSchema) {
|
|
382
|
-
super({
|
|
383
|
-
type: 'array',
|
|
384
|
-
items: itemsSchema.build(),
|
|
385
|
-
});
|
|
386
|
-
}
|
|
387
|
-
min(minItems) {
|
|
388
|
-
Object.assign(this.schema, { minItems });
|
|
389
|
-
return this;
|
|
390
|
-
}
|
|
391
|
-
max(maxItems) {
|
|
392
|
-
Object.assign(this.schema, { maxItems });
|
|
393
|
-
return this;
|
|
394
|
-
}
|
|
395
|
-
unique(uniqueItems = true) {
|
|
396
|
-
Object.assign(this.schema, { uniqueItems });
|
|
397
|
-
return this;
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
export class JsonSchemaTupleBuilder extends JsonSchemaAnyBuilder {
|
|
401
|
-
constructor(items) {
|
|
402
|
-
super({
|
|
403
|
-
type: 'array',
|
|
404
|
-
items: items.map(b => b.build()),
|
|
405
|
-
minItems: items.length,
|
|
406
|
-
maxItems: items.length,
|
|
407
|
-
});
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
function object(props) {
|
|
411
|
-
return new JsonSchemaObjectBuilder().addProperties(props);
|
|
412
|
-
}
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
import { _uniq } from '../../array/index.js'
|
|
2
|
-
import { _stringMapEntries, type AnyObject, type StringMap } from '../../types.js'
|
|
3
|
-
import type {
|
|
4
|
-
JsonSchema,
|
|
5
|
-
JsonSchemaArray,
|
|
6
|
-
JsonSchemaBoolean,
|
|
7
|
-
JsonSchemaNull,
|
|
8
|
-
JsonSchemaNumber,
|
|
9
|
-
JsonSchemaObject,
|
|
10
|
-
JsonSchemaOneOf,
|
|
11
|
-
JsonSchemaString,
|
|
12
|
-
} from '../index.js'
|
|
13
|
-
|
|
14
|
-
type PrimitiveType = 'undefined' | 'null' | 'boolean' | 'string' | 'number'
|
|
15
|
-
type Type = PrimitiveType | 'array' | 'object'
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Each row must be an object (current limitation).
|
|
19
|
-
*
|
|
20
|
-
* `additionalProperties` is set to `true`, cause it's safer.
|
|
21
|
-
*/
|
|
22
|
-
export function generateJsonSchemaFromData<T extends AnyObject = AnyObject>(
|
|
23
|
-
rows: AnyObject[],
|
|
24
|
-
): JsonSchemaObject<T> {
|
|
25
|
-
return objectToJsonSchema(rows as any) as JsonSchemaObject<T>
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function objectToJsonSchema(rows: AnyObject[]): JsonSchemaObject {
|
|
29
|
-
const typesByKey: StringMap<Set<Type>> = {}
|
|
30
|
-
|
|
31
|
-
rows.forEach(r => {
|
|
32
|
-
Object.keys(r).forEach(key => {
|
|
33
|
-
typesByKey[key] ||= new Set<Type>()
|
|
34
|
-
typesByKey[key].add(getTypeOfValue(r[key]))
|
|
35
|
-
})
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
const s: JsonSchemaObject = {
|
|
39
|
-
type: 'object',
|
|
40
|
-
properties: {},
|
|
41
|
-
required: [],
|
|
42
|
-
additionalProperties: true,
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
_stringMapEntries(typesByKey).forEach(([key, types]) => {
|
|
46
|
-
const schema = mergeTypes(
|
|
47
|
-
[...types],
|
|
48
|
-
rows.map(r => r[key]),
|
|
49
|
-
)
|
|
50
|
-
if (!schema) return
|
|
51
|
-
s.properties[key] = schema
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
// console.log(typesByKey)
|
|
55
|
-
|
|
56
|
-
return s
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function mergeTypes(types: Type[], samples: any[]): JsonSchema | undefined {
|
|
60
|
-
// skip "undefined" types
|
|
61
|
-
types = types.filter(t => t !== 'undefined')
|
|
62
|
-
|
|
63
|
-
if (!types.length) return undefined
|
|
64
|
-
|
|
65
|
-
if (types.length > 1) {
|
|
66
|
-
// oneOf
|
|
67
|
-
const s: JsonSchemaOneOf = {
|
|
68
|
-
oneOf: types.map(type => mergeTypes([type], samples)!),
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return s
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const type = types[0]!
|
|
75
|
-
|
|
76
|
-
if (type === 'null') {
|
|
77
|
-
return {
|
|
78
|
-
type: 'null',
|
|
79
|
-
} as JsonSchemaNull
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
if (type === 'boolean') {
|
|
83
|
-
return {
|
|
84
|
-
type: 'boolean',
|
|
85
|
-
} as JsonSchemaBoolean
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (type === 'string') {
|
|
89
|
-
return {
|
|
90
|
-
type: 'string',
|
|
91
|
-
} as JsonSchemaString
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if (type === 'number') {
|
|
95
|
-
return {
|
|
96
|
-
type: 'number',
|
|
97
|
-
} as JsonSchemaNumber
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (type === 'object') {
|
|
101
|
-
return objectToJsonSchema(samples.filter((r: any) => r && typeof r === 'object'))
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (type === 'array') {
|
|
105
|
-
// possible feature: detect if it's a tuple
|
|
106
|
-
// currently assume no-tuple
|
|
107
|
-
const items = samples.filter(r => Array.isArray(r)).flat()
|
|
108
|
-
const itemTypes = _uniq(items.map(i => getTypeOfValue(i)))
|
|
109
|
-
|
|
110
|
-
return {
|
|
111
|
-
type: 'array',
|
|
112
|
-
items: mergeTypes(itemTypes, items),
|
|
113
|
-
} as JsonSchemaArray
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function getTypeOfValue(v: any): Type {
|
|
118
|
-
if (v === null) return 'null'
|
|
119
|
-
if (Array.isArray(v)) return 'array'
|
|
120
|
-
return typeof v as Type
|
|
121
|
-
}
|