yuppi 1.3.22 → 1.4.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/README.md +44 -6
- package/dist/main.d.mts +4 -1
- package/dist/main.d.ts +4 -1
- package/dist/main.js +38 -3
- package/dist/main.mjs +48 -13
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -65,7 +65,7 @@ Schemas that can be converted to Yup and JSON Schema.
|
|
|
65
65
|
- Portable schemas as a JSON file
|
|
66
66
|
- Works with Yup, stable and secure
|
|
67
67
|
- Schemas can be declared for TypeScript
|
|
68
|
-
- It
|
|
68
|
+
- It has union support, properties can have multiple types
|
|
69
69
|
- Error messages are ready to be understood but can be edited if desired
|
|
70
70
|
- Can be converted to Yup and [JSON Schema](https://json-schema.org). JSON Schema is OpenAPI compatible
|
|
71
71
|
|
|
@@ -185,13 +185,34 @@ Validate the properties with your Yuppi schema.
|
|
|
185
185
|
> lowercase: true,
|
|
186
186
|
> nullable: false,
|
|
187
187
|
> required: true
|
|
188
|
-
> }
|
|
188
|
+
> },
|
|
189
|
+
>
|
|
190
|
+
> permissions: [
|
|
191
|
+
> {
|
|
192
|
+
> type: 'string',
|
|
193
|
+
> enum: ['*'],
|
|
194
|
+
> nullable: false,
|
|
195
|
+
> required: true
|
|
196
|
+
> },
|
|
197
|
+
> {
|
|
198
|
+
> type: 'array',
|
|
199
|
+
> items: {
|
|
200
|
+
> type: 'string',
|
|
201
|
+
> enum: ['read', 'write'],
|
|
202
|
+
> nullable: false,
|
|
203
|
+
> required: true
|
|
204
|
+
> },
|
|
205
|
+
> nullable: false,
|
|
206
|
+
> required: true
|
|
207
|
+
> }
|
|
208
|
+
> ]
|
|
189
209
|
> };
|
|
190
210
|
>
|
|
191
211
|
> const properties = {
|
|
192
212
|
> display_name: 'Fırat',
|
|
193
213
|
> username: 'fir4tozden',
|
|
194
|
-
> email: 'fir4tozden@gmail.com'
|
|
214
|
+
> email: 'fir4tozden@gmail.com',
|
|
215
|
+
> permissions: '*'
|
|
195
216
|
> };
|
|
196
217
|
>
|
|
197
218
|
> try {
|
|
@@ -200,7 +221,8 @@ Validate the properties with your Yuppi schema.
|
|
|
200
221
|
> {
|
|
201
222
|
> display_name: "Fırat",
|
|
202
223
|
> username: "fir4tozden",
|
|
203
|
-
> email: "fir4tozden@gmail.com"
|
|
224
|
+
> email: "fir4tozden@gmail.com",
|
|
225
|
+
> permissions: "*"
|
|
204
226
|
> }
|
|
205
227
|
> */
|
|
206
228
|
> } catch (error) {
|
|
@@ -236,6 +258,7 @@ Declare your Yuppi schema for TypeScript.
|
|
|
236
258
|
> display_name: string;
|
|
237
259
|
> username: string;
|
|
238
260
|
> email: string;
|
|
261
|
+
> permissions: "*" | ("read" | "write")[];
|
|
239
262
|
> }
|
|
240
263
|
> */
|
|
241
264
|
> ```
|
|
@@ -291,11 +314,26 @@ Convert your Yuppi schema into [JSON Schema](https://json-schema.org).
|
|
|
291
314
|
> email: {
|
|
292
315
|
> type: "string",
|
|
293
316
|
> pattern: "^[a-zA-Z0-9._-]+@([a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,}$"
|
|
317
|
+
> },
|
|
318
|
+
> permissions: {
|
|
319
|
+
> anyOf: [
|
|
320
|
+
> {
|
|
321
|
+
> type: "string",
|
|
322
|
+
> enum: ["*"]
|
|
323
|
+
> },
|
|
324
|
+
> {
|
|
325
|
+
> type: "array",
|
|
326
|
+
> items: {
|
|
327
|
+
> type: "string",
|
|
328
|
+
> enum: ["read", "write"]
|
|
329
|
+
> }
|
|
330
|
+
> }
|
|
331
|
+
> ]
|
|
294
332
|
> }
|
|
295
333
|
> },
|
|
296
|
-
> required: [
|
|
334
|
+
> required: ["display_name", "username", "email", "permissions"],
|
|
297
335
|
> additionalProperties: false
|
|
298
|
-
> }
|
|
336
|
+
> };
|
|
299
337
|
> */
|
|
300
338
|
> ```
|
|
301
339
|
|
package/dist/main.d.mts
CHANGED
|
@@ -60,7 +60,9 @@ type Array = {
|
|
|
60
60
|
nullable: boolean;
|
|
61
61
|
required: boolean;
|
|
62
62
|
};
|
|
63
|
-
type
|
|
63
|
+
type Type = String | Number | Boolean | Date | Object$1 | Array;
|
|
64
|
+
type Union = [Type, Type, ...Type[]];
|
|
65
|
+
type Types = Type | Union;
|
|
64
66
|
type Schema = Record<string, Types>;
|
|
65
67
|
|
|
66
68
|
type YuppiOptions = {
|
|
@@ -109,6 +111,7 @@ type YuppiOptions = {
|
|
|
109
111
|
declare class Yuppi {
|
|
110
112
|
private readonly options;
|
|
111
113
|
constructor(options?: YuppiOptions);
|
|
114
|
+
private cleanupTypesDir;
|
|
112
115
|
validate(schema: Schema, properties: AnyObject): Promise<{
|
|
113
116
|
[x: string]: any;
|
|
114
117
|
[x: number]: any;
|
package/dist/main.d.ts
CHANGED
|
@@ -60,7 +60,9 @@ type Array = {
|
|
|
60
60
|
nullable: boolean;
|
|
61
61
|
required: boolean;
|
|
62
62
|
};
|
|
63
|
-
type
|
|
63
|
+
type Type = String | Number | Boolean | Date | Object$1 | Array;
|
|
64
|
+
type Union = [Type, Type, ...Type[]];
|
|
65
|
+
type Types = Type | Union;
|
|
64
66
|
type Schema = Record<string, Types>;
|
|
65
67
|
|
|
66
68
|
type YuppiOptions = {
|
|
@@ -109,6 +111,7 @@ type YuppiOptions = {
|
|
|
109
111
|
declare class Yuppi {
|
|
110
112
|
private readonly options;
|
|
111
113
|
constructor(options?: YuppiOptions);
|
|
114
|
+
private cleanupTypesDir;
|
|
112
115
|
validate(schema: Schema, properties: AnyObject): Promise<{
|
|
113
116
|
[x: string]: any;
|
|
114
117
|
[x: number]: any;
|
package/dist/main.js
CHANGED
|
@@ -49,7 +49,7 @@ var convertToJSONSchema = (schema, options) => {
|
|
|
49
49
|
if (!config.required) schema2 = import_typebox.Type.Optional(schema2);
|
|
50
50
|
return schema2;
|
|
51
51
|
};
|
|
52
|
-
const
|
|
52
|
+
const buildSingle = (key, config) => {
|
|
53
53
|
let schema2;
|
|
54
54
|
if (config.type === "string") {
|
|
55
55
|
schema2 = import_typebox.Type.String({ enum: config.enum, minLength: config.min, maxLength: config.max, pattern: config.pattern !== void 0 ? new RegExp(config.pattern).source : void 0, default: config.default });
|
|
@@ -83,6 +83,13 @@ var convertToJSONSchema = (schema, options) => {
|
|
|
83
83
|
return schema2;
|
|
84
84
|
} else throw new Error(`Unsupported schema type for ${key}`);
|
|
85
85
|
};
|
|
86
|
+
const build = (key, config) => {
|
|
87
|
+
if (!Array.isArray(config)) return buildSingle(key, config);
|
|
88
|
+
const schemas = config.map((config2) => buildSingle(key, config2));
|
|
89
|
+
const optional = config.every((config2) => !config2.required);
|
|
90
|
+
const union_schema = import_typebox.Type.Union(schemas);
|
|
91
|
+
return optional ? import_typebox.Type.Optional(union_schema) : union_schema;
|
|
92
|
+
};
|
|
86
93
|
const properties = {};
|
|
87
94
|
for (const [key, config] of Object.entries(schema)) properties[key] = build(key, config);
|
|
88
95
|
return import_typebox.Type.Object(properties, { additionalProperties: !(options.validate_options?.stripUnknown ?? false) });
|
|
@@ -92,6 +99,7 @@ var convertToJSONSchema = (schema, options) => {
|
|
|
92
99
|
var Yup = __toESM(require("yup"));
|
|
93
100
|
var convertToYup = (schema, options) => {
|
|
94
101
|
const base = (schema2, key, config) => {
|
|
102
|
+
schema2 = schema2.strict();
|
|
95
103
|
schema2 = schema2.nullable();
|
|
96
104
|
schema2 = schema2.optional();
|
|
97
105
|
if (config.default !== void 0) schema2 = schema2.default(config.default);
|
|
@@ -108,7 +116,7 @@ var convertToYup = (schema, options) => {
|
|
|
108
116
|
);
|
|
109
117
|
return schema2;
|
|
110
118
|
};
|
|
111
|
-
const
|
|
119
|
+
const buildSingle = (key, config) => {
|
|
112
120
|
let schema2;
|
|
113
121
|
if (config.type === "string") {
|
|
114
122
|
schema2 = Yup.string().typeError(({ path: path2 }) => (options.error_messages?.string?.type ?? "").replaceAll("{path}", path2));
|
|
@@ -152,6 +160,7 @@ var convertToYup = (schema, options) => {
|
|
|
152
160
|
if (config.min !== void 0) schema2 = schema2.min(config.min, ({ path: path2, min }) => (options.error_messages?.date?.min ?? "").replaceAll("{path}", path2).replaceAll("{min}", new Date(min).toISOString()));
|
|
153
161
|
if (config.max !== void 0) schema2 = schema2.max(config.max, ({ path: path2, max }) => (options.error_messages?.date?.max ?? "").replaceAll("{path}", path2).replaceAll("{max}", new Date(max).toISOString()));
|
|
154
162
|
schema2 = base(schema2, key, config);
|
|
163
|
+
schema2 = schema2.strict(false);
|
|
155
164
|
return schema2;
|
|
156
165
|
} else if (config.type === "object") {
|
|
157
166
|
schema2 = Yup.object().typeError(({ path: path2 }) => (options.error_messages?.object?.type ?? "").replaceAll("{path}", path2));
|
|
@@ -175,7 +184,15 @@ var convertToYup = (schema, options) => {
|
|
|
175
184
|
schema2 = schema2.of(build(key, config.items));
|
|
176
185
|
schema2 = base(schema2, key, config);
|
|
177
186
|
return schema2;
|
|
178
|
-
}
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
const build = (key, config) => {
|
|
190
|
+
if (!Array.isArray(config)) return buildSingle(key, config);
|
|
191
|
+
const schemas = config.map((config2) => buildSingle(key, config2));
|
|
192
|
+
return Yup.lazy((property) => {
|
|
193
|
+
for (const schema2 of schemas) if (schema2.isValidSync(property)) return schema2;
|
|
194
|
+
return buildSingle(key, config[0]);
|
|
195
|
+
});
|
|
179
196
|
};
|
|
180
197
|
const properties = {};
|
|
181
198
|
for (const [key, config] of Object.entries(schema)) properties[key] = build(key, config);
|
|
@@ -235,10 +252,28 @@ var YuppiOptionsDefault = {
|
|
|
235
252
|
};
|
|
236
253
|
|
|
237
254
|
// src/Yuppi.class.ts
|
|
255
|
+
var cleaned_types_dirs = /* @__PURE__ */ new Set();
|
|
238
256
|
var Yuppi = class {
|
|
239
257
|
options;
|
|
240
258
|
constructor(options = YuppiOptionsDefault) {
|
|
241
259
|
this.options = (0, import_lodash.default)({}, YuppiOptionsDefault, options);
|
|
260
|
+
void this.cleanupTypesDir();
|
|
261
|
+
}
|
|
262
|
+
async cleanupTypesDir() {
|
|
263
|
+
const types_dir = import_path.default.join(this.options.output_dir ?? "./", "types");
|
|
264
|
+
const exists = async (path2) => {
|
|
265
|
+
try {
|
|
266
|
+
await import_promises.default.access(path2, import_promises.default.constants.F_OK);
|
|
267
|
+
return true;
|
|
268
|
+
} catch {
|
|
269
|
+
return false;
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
if (await exists(types_dir) && !cleaned_types_dirs.has(types_dir)) {
|
|
273
|
+
cleaned_types_dirs.add(types_dir);
|
|
274
|
+
await import_promises.default.rm(types_dir, { recursive: true, force: true });
|
|
275
|
+
await import_promises.default.mkdir(types_dir, { recursive: true });
|
|
276
|
+
}
|
|
242
277
|
}
|
|
243
278
|
validate(schema, properties) {
|
|
244
279
|
const yup_schema = this.convertToYup(schema);
|
package/dist/main.mjs
CHANGED
|
@@ -11,17 +11,17 @@ import fs from "fs/promises";
|
|
|
11
11
|
import path from "path";
|
|
12
12
|
|
|
13
13
|
// src/utils/ConvertToJSONSchema.util.ts
|
|
14
|
-
import { Type } from "@sinclair/typebox";
|
|
14
|
+
import { Type as Typebox } from "@sinclair/typebox";
|
|
15
15
|
var convertToJSONSchema = (schema, options) => {
|
|
16
16
|
const base = (schema2, key, config) => {
|
|
17
|
-
if (config.nullable || config.default === null) schema2 =
|
|
18
|
-
if (!config.required) schema2 =
|
|
17
|
+
if (config.nullable || config.default === null) schema2 = Typebox.Union([schema2, Typebox.Null()]);
|
|
18
|
+
if (!config.required) schema2 = Typebox.Optional(schema2);
|
|
19
19
|
return schema2;
|
|
20
20
|
};
|
|
21
|
-
const
|
|
21
|
+
const buildSingle = (key, config) => {
|
|
22
22
|
let schema2;
|
|
23
23
|
if (config.type === "string") {
|
|
24
|
-
schema2 =
|
|
24
|
+
schema2 = Typebox.String({ enum: config.enum, minLength: config.min, maxLength: config.max, pattern: config.pattern !== void 0 ? new RegExp(config.pattern).source : void 0, default: config.default });
|
|
25
25
|
schema2 = base(schema2, key, config);
|
|
26
26
|
return schema2;
|
|
27
27
|
} else if (config.type === "number") {
|
|
@@ -29,38 +29,46 @@ var convertToJSONSchema = (schema, options) => {
|
|
|
29
29
|
let exclusive_maximum;
|
|
30
30
|
if (config.positive === true && config.min === void 0) exclusive_minimum = 0;
|
|
31
31
|
if (config.negative === true && config.max === void 0) exclusive_maximum = 0;
|
|
32
|
-
schema2 = config.integer === true ?
|
|
32
|
+
schema2 = config.integer === true ? Typebox.Integer({ enum: config.enum, minimum: config.min, maximum: config.max, exclusiveMinimum: exclusive_minimum, exclusiveMaximum: exclusive_maximum, positive: config.positive, negative: config.negative, default: config.default }) : Typebox.Number({ enum: config.enum, minimum: config.min, maximum: config.max, exclusiveMinimum: exclusive_minimum, exclusiveMaximum: exclusive_maximum, positive: config.positive, negative: config.negative, default: config.default });
|
|
33
33
|
schema2 = base(schema2, key, config);
|
|
34
34
|
return schema2;
|
|
35
35
|
} else if (config.type === "boolean") {
|
|
36
|
-
schema2 =
|
|
36
|
+
schema2 = Typebox.Boolean({ default: config.default });
|
|
37
37
|
schema2 = base(schema2, key, config);
|
|
38
38
|
return schema2;
|
|
39
39
|
} else if (config.type === "date") {
|
|
40
|
-
schema2 =
|
|
40
|
+
schema2 = Typebox.String({ format: "date-time", formatMinimum: config.min !== void 0 ? new Date(config.min).toISOString() : void 0, formatMaximum: config.max !== void 0 ? new Date(config.max).toISOString() : void 0, default: config.default });
|
|
41
41
|
schema2 = base(schema2, key, config);
|
|
42
42
|
return schema2;
|
|
43
43
|
} else if (config.type === "object") {
|
|
44
44
|
const nested_properties = {};
|
|
45
45
|
for (const [nested_key, nested_config] of Object.entries(config.properties)) nested_properties[nested_key] = build(nested_key, nested_config);
|
|
46
|
-
schema2 =
|
|
46
|
+
schema2 = Typebox.Object(nested_properties, { default: config.default, additionalProperties: !(options.validate_options?.stripUnknown ?? false) });
|
|
47
47
|
schema2 = base(schema2, key, config);
|
|
48
48
|
return schema2;
|
|
49
49
|
} else if (config.type === "array") {
|
|
50
|
-
schema2 =
|
|
50
|
+
schema2 = Typebox.Array(build(key, config.items), { minItems: config.min, maxItems: config.max, default: config.default });
|
|
51
51
|
schema2 = base(schema2, key, config);
|
|
52
52
|
return schema2;
|
|
53
53
|
} else throw new Error(`Unsupported schema type for ${key}`);
|
|
54
54
|
};
|
|
55
|
+
const build = (key, config) => {
|
|
56
|
+
if (!Array.isArray(config)) return buildSingle(key, config);
|
|
57
|
+
const schemas = config.map((config2) => buildSingle(key, config2));
|
|
58
|
+
const optional = config.every((config2) => !config2.required);
|
|
59
|
+
const union_schema = Typebox.Union(schemas);
|
|
60
|
+
return optional ? Typebox.Optional(union_schema) : union_schema;
|
|
61
|
+
};
|
|
55
62
|
const properties = {};
|
|
56
63
|
for (const [key, config] of Object.entries(schema)) properties[key] = build(key, config);
|
|
57
|
-
return
|
|
64
|
+
return Typebox.Object(properties, { additionalProperties: !(options.validate_options?.stripUnknown ?? false) });
|
|
58
65
|
};
|
|
59
66
|
|
|
60
67
|
// src/utils/ConvertToYup.util.ts
|
|
61
68
|
import * as Yup from "yup";
|
|
62
69
|
var convertToYup = (schema, options) => {
|
|
63
70
|
const base = (schema2, key, config) => {
|
|
71
|
+
schema2 = schema2.strict();
|
|
64
72
|
schema2 = schema2.nullable();
|
|
65
73
|
schema2 = schema2.optional();
|
|
66
74
|
if (config.default !== void 0) schema2 = schema2.default(config.default);
|
|
@@ -77,7 +85,7 @@ var convertToYup = (schema, options) => {
|
|
|
77
85
|
);
|
|
78
86
|
return schema2;
|
|
79
87
|
};
|
|
80
|
-
const
|
|
88
|
+
const buildSingle = (key, config) => {
|
|
81
89
|
let schema2;
|
|
82
90
|
if (config.type === "string") {
|
|
83
91
|
schema2 = Yup.string().typeError(({ path: path2 }) => (options.error_messages?.string?.type ?? "").replaceAll("{path}", path2));
|
|
@@ -121,6 +129,7 @@ var convertToYup = (schema, options) => {
|
|
|
121
129
|
if (config.min !== void 0) schema2 = schema2.min(config.min, ({ path: path2, min }) => (options.error_messages?.date?.min ?? "").replaceAll("{path}", path2).replaceAll("{min}", new Date(min).toISOString()));
|
|
122
130
|
if (config.max !== void 0) schema2 = schema2.max(config.max, ({ path: path2, max }) => (options.error_messages?.date?.max ?? "").replaceAll("{path}", path2).replaceAll("{max}", new Date(max).toISOString()));
|
|
123
131
|
schema2 = base(schema2, key, config);
|
|
132
|
+
schema2 = schema2.strict(false);
|
|
124
133
|
return schema2;
|
|
125
134
|
} else if (config.type === "object") {
|
|
126
135
|
schema2 = Yup.object().typeError(({ path: path2 }) => (options.error_messages?.object?.type ?? "").replaceAll("{path}", path2));
|
|
@@ -144,7 +153,15 @@ var convertToYup = (schema, options) => {
|
|
|
144
153
|
schema2 = schema2.of(build(key, config.items));
|
|
145
154
|
schema2 = base(schema2, key, config);
|
|
146
155
|
return schema2;
|
|
147
|
-
}
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
const build = (key, config) => {
|
|
159
|
+
if (!Array.isArray(config)) return buildSingle(key, config);
|
|
160
|
+
const schemas = config.map((config2) => buildSingle(key, config2));
|
|
161
|
+
return Yup.lazy((property) => {
|
|
162
|
+
for (const schema2 of schemas) if (schema2.isValidSync(property)) return schema2;
|
|
163
|
+
return buildSingle(key, config[0]);
|
|
164
|
+
});
|
|
148
165
|
};
|
|
149
166
|
const properties = {};
|
|
150
167
|
for (const [key, config] of Object.entries(schema)) properties[key] = build(key, config);
|
|
@@ -204,10 +221,28 @@ var YuppiOptionsDefault = {
|
|
|
204
221
|
};
|
|
205
222
|
|
|
206
223
|
// src/Yuppi.class.ts
|
|
224
|
+
var cleaned_types_dirs = /* @__PURE__ */ new Set();
|
|
207
225
|
var Yuppi = class {
|
|
208
226
|
options;
|
|
209
227
|
constructor(options = YuppiOptionsDefault) {
|
|
210
228
|
this.options = merge({}, YuppiOptionsDefault, options);
|
|
229
|
+
void this.cleanupTypesDir();
|
|
230
|
+
}
|
|
231
|
+
async cleanupTypesDir() {
|
|
232
|
+
const types_dir = path.join(this.options.output_dir ?? "./", "types");
|
|
233
|
+
const exists = async (path2) => {
|
|
234
|
+
try {
|
|
235
|
+
await fs.access(path2, fs.constants.F_OK);
|
|
236
|
+
return true;
|
|
237
|
+
} catch {
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
if (await exists(types_dir) && !cleaned_types_dirs.has(types_dir)) {
|
|
242
|
+
cleaned_types_dirs.add(types_dir);
|
|
243
|
+
await fs.rm(types_dir, { recursive: true, force: true });
|
|
244
|
+
await fs.mkdir(types_dir, { recursive: true });
|
|
245
|
+
}
|
|
211
246
|
}
|
|
212
247
|
validate(schema, properties) {
|
|
213
248
|
const yup_schema = this.convertToYup(schema);
|