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 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 is strict and therefore does not accept more than one type
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: [ "display_name", "username", "email" ],
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 Types = String | Number | Boolean | Date | Object$1 | Array;
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 Types = String | Number | Boolean | Date | Object$1 | Array;
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 build = (key, config) => {
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 build = (key, config) => {
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
- } else throw new Error(`Unsupported schema type for ${key}`);
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 = Type.Union([schema2, Type.Null()]);
18
- if (!config.required) schema2 = Type.Optional(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 build = (key, config) => {
21
+ const buildSingle = (key, config) => {
22
22
  let schema2;
23
23
  if (config.type === "string") {
24
- schema2 = 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 });
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 ? Type.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 }) : Type.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 });
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 = Type.Boolean({ default: config.default });
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 = Type.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 });
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 = Type.Object(nested_properties, { default: config.default, additionalProperties: !(options.validate_options?.stripUnknown ?? false) });
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 = Type.Array(build(key, config.items), { minItems: config.min, maxItems: config.max, default: config.default });
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 Type.Object(properties, { additionalProperties: !(options.validate_options?.stripUnknown ?? false) });
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 build = (key, config) => {
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
- } else throw new Error(`Unsupported schema type for ${key}`);
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);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yuppi",
3
- "version": "1.3.22",
3
+ "version": "1.4.0",
4
4
  "description": "Schemas that can be converted to Yup and JSON Schema.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/keift/yuppi",