yuppi 1.2.11 → 1.3.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
@@ -99,11 +99,11 @@ Yuppi
99
99
  ├── new Yuppi(options?)
100
100
  │ │
101
101
  │ ├── validate(schema, properties)
102
+ │ ├── declare(schema, name)
102
103
  │ ├── convertToYup(schema)
103
104
  │ └── convertToJSONSchema(schema)
104
105
 
105
106
  ├── Patterns
106
- │ ├── Any
107
107
  │ ├── Domain
108
108
  │ ├── Email
109
109
  │ ├── HTTP
@@ -210,6 +210,36 @@ Validate the properties with your Yuppi schema.
210
210
 
211
211
  <br/>
212
212
 
213
+ `Yuppi.declare(schema, name)`
214
+
215
+ Declare your Yuppi schema for TypeScript.
216
+
217
+ > | Parameter | Default | Description |
218
+ > | --------- | ------- | ------------------------------ |
219
+ > | schema | | [Schema]<br/>Yuppi schema. |
220
+ > | name | | [String]<br/>Declaration name. |
221
+ >
222
+ > returns [Void]
223
+ >
224
+ > Example:
225
+ >
226
+ > ```typescript
227
+ > import type { User } from './yuppi/types/user';
228
+ >
229
+ > Yupp.declare(schema, 'user');
230
+ >
231
+ > const user = Yupp.validate(schema, properties) as User;
232
+ > /*
233
+ > interface User {
234
+ > display_name: string;
235
+ > username: string;
236
+ > email: string;
237
+ > }
238
+ > */
239
+ > ```
240
+
241
+ <br/>
242
+
213
243
  `Yuppi.convertToYup(schema)`
214
244
 
215
245
  Convert your Yuppi schema into Yup schema.
@@ -223,33 +253,6 @@ Convert your Yuppi schema into Yup schema.
223
253
  > Example:
224
254
  >
225
255
  > ```typescript
226
- > const schema: Schema = {
227
- > display_name: {
228
- > type: 'string',
229
- > min: 1,
230
- > max: 32,
231
- > nullable: false,
232
- > required: true
233
- > },
234
- >
235
- > username: {
236
- > type: 'string',
237
- > min: 3,
238
- > max: 16,
239
- > pattern: Patterns.Username,
240
- > nullable: false,
241
- > required: true
242
- > },
243
- >
244
- > email: {
245
- > type: 'string',
246
- > pattern: Patterns.Email,
247
- > lowercase: true,
248
- > nullable: false,
249
- > required: true
250
- > }
251
- > };
252
- >
253
256
  > Yupp.convertToYup(schema);
254
257
  > ```
255
258
 
@@ -268,33 +271,6 @@ Convert your Yuppi schema into [JSON Schema](https://json-schema.org).
268
271
  > Example:
269
272
  >
270
273
  > ```typescript
271
- > const schema: Schema = {
272
- > display_name: {
273
- > type: 'string',
274
- > min: 1,
275
- > max: 32,
276
- > nullable: false,
277
- > required: true
278
- > },
279
- >
280
- > username: {
281
- > type: 'string',
282
- > min: 3,
283
- > max: 16,
284
- > pattern: Patterns.Username,
285
- > nullable: false,
286
- > required: true
287
- > },
288
- >
289
- > email: {
290
- > type: 'string',
291
- > pattern: Patterns.Email,
292
- > lowercase: true,
293
- > nullable: false,
294
- > required: true
295
- > }
296
- > };
297
- >
298
274
  > Yupp.convertToJSONSchema(schema);
299
275
  > /*
300
276
  > {
@@ -320,7 +296,8 @@ Convert your Yuppi schema into [JSON Schema](https://json-schema.org).
320
296
  > "display_name",
321
297
  > "username",
322
298
  > "email"
323
- > ]
299
+ > ],
300
+ > additionalProperties: false
324
301
  > }
325
302
  > */
326
303
  > ```
package/dist/main.d.mts CHANGED
@@ -66,6 +66,7 @@ type Schema = Record<string, Types>;
66
66
  type ValidateOptions = ValidateOptions$1;
67
67
 
68
68
  type YuppiOptions = {
69
+ folder_path?: string;
69
70
  error_messages?: {
70
71
  base?: {
71
72
  nullable?: string;
@@ -114,6 +115,7 @@ declare class Yuppi {
114
115
  [x: string]: any;
115
116
  [x: number]: any;
116
117
  };
118
+ declare(schema: Schema, name: string): void;
117
119
  convertToYup(schema: Schema): yup.ObjectSchema<{
118
120
  [x: string]: any;
119
121
  }, yup.AnyObject, {
package/dist/main.d.ts CHANGED
@@ -66,6 +66,7 @@ type Schema = Record<string, Types>;
66
66
  type ValidateOptions = ValidateOptions$1;
67
67
 
68
68
  type YuppiOptions = {
69
+ folder_path?: string;
69
70
  error_messages?: {
70
71
  base?: {
71
72
  nullable?: string;
@@ -114,6 +115,7 @@ declare class Yuppi {
114
115
  [x: string]: any;
115
116
  [x: number]: any;
116
117
  };
118
+ declare(schema: Schema, name: string): void;
117
119
  convertToYup(schema: Schema): yup.ObjectSchema<{
118
120
  [x: string]: any;
119
121
  }, yup.AnyObject, {
package/dist/main.js CHANGED
@@ -36,7 +36,53 @@ __export(main_exports, {
36
36
  module.exports = __toCommonJS(main_exports);
37
37
 
38
38
  // src/Yuppi.class.ts
39
+ var import_json_schema_to_typescript = require("json-schema-to-typescript");
39
40
  var import_lodash = __toESM(require("lodash"));
41
+ var import_fs = __toESM(require("fs"));
42
+ var import_path = __toESM(require("path"));
43
+
44
+ // src/utils/ConvertToJSONSchema.util.ts
45
+ var import_typebox = require("@sinclair/typebox");
46
+ var convertToJSONSchema = (schema) => {
47
+ const base = (schema2, key, config) => {
48
+ if (!config.required) schema2 = import_typebox.Type.Optional(schema2);
49
+ if (config.nullable || config.default === null) schema2 = import_typebox.Type.Union([schema2, import_typebox.Type.Null()]);
50
+ return schema2;
51
+ };
52
+ const build = (key, config) => {
53
+ let schema2;
54
+ if (config.type === "string") {
55
+ schema2 = import_typebox.Type.String({ enum: config.enum, minLength: config.min, maxLength: config.max, pattern: config.pattern ? new RegExp(config.pattern).source : void 0, default: config.default });
56
+ schema2 = base(schema2, key, config);
57
+ return schema2;
58
+ } else if (config.type === "number") {
59
+ schema2 = config.integer === true ? import_typebox.Type.Integer({ enum: config.enum, minimum: config.min, maximum: config.max, default: config.default }) : import_typebox.Type.Number({ enum: config.enum, minimum: config.min, maximum: config.max, default: config.default });
60
+ schema2 = base(schema2, key, config);
61
+ return schema2;
62
+ } else if (config.type === "boolean") {
63
+ schema2 = import_typebox.Type.Boolean({ default: config.default });
64
+ schema2 = base(schema2, key, config);
65
+ return schema2;
66
+ } else if (config.type === "date") {
67
+ schema2 = import_typebox.Type.String({ format: "date-time", minimum: config.min, maximum: config.max, default: config.default });
68
+ schema2 = base(schema2, key, config);
69
+ return schema2;
70
+ } else if (config.type === "object") {
71
+ const nested_properties = {};
72
+ for (const [nested_key, nested_config] of Object.entries(config.properties)) nested_properties[nested_key] = build(nested_key, nested_config);
73
+ schema2 = import_typebox.Type.Object(nested_properties, { additionalProperties: false });
74
+ schema2 = base(schema2, key, config);
75
+ return schema2;
76
+ } else if (config.type === "array") {
77
+ schema2 = import_typebox.Type.Array(build(key, config.items), { minItems: config.min, maxItems: config.max, default: config.default });
78
+ schema2 = base(schema2, key, config);
79
+ return schema2;
80
+ } else throw new Error(`Unsupported schema type for ${key}`);
81
+ };
82
+ const properties = {};
83
+ for (const [key, config] of Object.entries(schema)) properties[key] = build(key, config);
84
+ return import_typebox.Type.Object(properties, { additionalProperties: false });
85
+ };
40
86
 
41
87
  // src/utils/ConvertToYup.util.ts
42
88
  var Yup = __toESM(require("yup"));
@@ -46,7 +92,7 @@ var convertToYup = (schema, error_messages) => {
46
92
  if (config.required)
47
93
  schema2 = schema2.test(
48
94
  "required",
49
- ({ path }) => (error_messages?.base?.required ?? "").replaceAll("{path}", path),
95
+ ({ path: path2 }) => (error_messages?.base?.required ?? "").replaceAll("{path}", path2),
50
96
  (property) => {
51
97
  if (property === void 0) return false;
52
98
  if (typeof property === "string" && property.trim() === "") return false;
@@ -54,74 +100,74 @@ var convertToYup = (schema, error_messages) => {
54
100
  return true;
55
101
  }
56
102
  );
57
- if (!config.nullable && config.default !== null) schema2 = schema2.nonNullable(({ path }) => (error_messages?.base?.nullable ?? "").replaceAll("{path}", path));
103
+ if (!config.nullable && config.default !== null) schema2 = schema2.nonNullable(({ path: path2 }) => (error_messages?.base?.nullable ?? "").replaceAll("{path}", path2));
58
104
  if (config.default) schema2 = schema2.default(config.default);
59
105
  return schema2;
60
106
  };
61
107
  const build = (key, config) => {
62
108
  let schema2;
63
109
  if (config.type === "string") {
64
- schema2 = Yup.string().typeError(({ path }) => (error_messages?.string?.type ?? "").replaceAll("{path}", path));
110
+ schema2 = Yup.string().typeError(({ path: path2 }) => (error_messages?.string?.type ?? "").replaceAll("{path}", path2));
65
111
  schema2 = base(schema2, key, config);
66
112
  schema2 = schema2.transform((property) => typeof property === "string" ? property.trim() : property);
67
113
  if (config.enum)
68
114
  schema2 = schema2.oneOf(
69
115
  config.enum.map((item) => item.trim()),
70
- ({ path }) => (error_messages?.string?.enum ?? "").replaceAll("{path}", path)
116
+ ({ path: path2 }) => (error_messages?.string?.enum ?? "").replaceAll("{path}", path2)
71
117
  );
72
- if (config.pattern) schema2 = schema2.matches(new RegExp(config.pattern), ({ path }) => (error_messages?.string?.pattern ?? "").replaceAll("{path}", path).replaceAll("{pattern}", config.pattern ? new RegExp(config.pattern).source : ""));
118
+ if (config.pattern) schema2 = schema2.matches(new RegExp(config.pattern), ({ path: path2 }) => (error_messages?.string?.pattern ?? "").replaceAll("{path}", path2).replaceAll("{pattern}", config.pattern ? new RegExp(config.pattern).source : ""));
73
119
  if (config.min)
74
120
  schema2 = schema2.min(
75
121
  config.min,
76
- ({ path, min }) => (error_messages?.string?.min ?? "").replaceAll("{path}", path).replaceAll("{min}", min.toString()).replaceAll("{plural_suffix}", min > 1 ? "s" : "")
122
+ ({ path: path2, min }) => (error_messages?.string?.min ?? "").replaceAll("{path}", path2).replaceAll("{min}", min.toString()).replaceAll("{plural_suffix}", min > 1 ? "s" : "")
77
123
  );
78
124
  if (config.max)
79
125
  schema2 = schema2.max(
80
126
  config.max,
81
- ({ path, max }) => (error_messages?.string?.max ?? "").replaceAll("{path}", path).replaceAll("{max}", max.toString()).replaceAll("{plural_suffix}", max > 1 ? "s" : "")
127
+ ({ path: path2, max }) => (error_messages?.string?.max ?? "").replaceAll("{path}", path2).replaceAll("{max}", max.toString()).replaceAll("{plural_suffix}", max > 1 ? "s" : "")
82
128
  );
83
129
  if (config.lowercase) schema2 = schema2.transform((property) => typeof property === "string" ? property.toLowerCase() : property);
84
130
  if (config.uppercase) schema2 = schema2.transform((property) => typeof property === "string" ? property.toUpperCase() : property);
85
131
  return schema2;
86
132
  } else if (config.type === "number") {
87
- schema2 = Yup.number().typeError(({ path }) => (error_messages?.number?.type ?? "").replaceAll("{path}", path));
133
+ schema2 = Yup.number().typeError(({ path: path2 }) => (error_messages?.number?.type ?? "").replaceAll("{path}", path2));
88
134
  schema2 = base(schema2, key, config);
89
- if (config.enum) schema2 = schema2.oneOf(config.enum, ({ path }) => (error_messages?.number?.enum ?? "").replaceAll("{path}", path));
90
- if (config.min) schema2 = schema2.min(config.min, ({ path, min }) => (error_messages?.number?.min ?? "").replaceAll("{path}", path).replaceAll("{min}", min.toString()));
91
- if (config.max) schema2 = schema2.max(config.max, ({ path, max }) => (error_messages?.number?.max ?? "").replaceAll("{path}", path).replaceAll("{max}", max.toString()));
92
- if (config.integer) schema2 = schema2.integer(({ path }) => (error_messages?.number?.integer ?? "").replaceAll("{path}", path));
93
- if (config.positive) schema2 = schema2.positive(({ path }) => (error_messages?.number?.positive ?? "").replaceAll("{path}", path));
94
- if (config.negative) schema2 = schema2.negative(({ path }) => (error_messages?.number?.negative ?? "").replaceAll("{path}", path));
135
+ if (config.enum) schema2 = schema2.oneOf(config.enum, ({ path: path2 }) => (error_messages?.number?.enum ?? "").replaceAll("{path}", path2));
136
+ if (config.min) schema2 = schema2.min(config.min, ({ path: path2, min }) => (error_messages?.number?.min ?? "").replaceAll("{path}", path2).replaceAll("{min}", min.toString()));
137
+ if (config.max) schema2 = schema2.max(config.max, ({ path: path2, max }) => (error_messages?.number?.max ?? "").replaceAll("{path}", path2).replaceAll("{max}", max.toString()));
138
+ if (config.integer) schema2 = schema2.integer(({ path: path2 }) => (error_messages?.number?.integer ?? "").replaceAll("{path}", path2));
139
+ if (config.positive) schema2 = schema2.positive(({ path: path2 }) => (error_messages?.number?.positive ?? "").replaceAll("{path}", path2));
140
+ if (config.negative) schema2 = schema2.negative(({ path: path2 }) => (error_messages?.number?.negative ?? "").replaceAll("{path}", path2));
95
141
  return schema2;
96
142
  } else if (config.type === "boolean") {
97
- schema2 = Yup.boolean().typeError(({ path }) => (error_messages?.boolean?.type ?? "").replaceAll("{path}", path));
143
+ schema2 = Yup.boolean().typeError(({ path: path2 }) => (error_messages?.boolean?.type ?? "").replaceAll("{path}", path2));
98
144
  schema2 = base(schema2, key, config);
99
145
  return schema2;
100
146
  } else if (config.type === "date") {
101
- schema2 = Yup.date().typeError(({ path }) => (error_messages?.date?.type ?? "").replaceAll("{path}", path));
147
+ schema2 = Yup.date().typeError(({ path: path2 }) => (error_messages?.date?.type ?? "").replaceAll("{path}", path2));
102
148
  schema2 = base(schema2, key, config);
103
- if (config.min) schema2 = schema2.min(config.min, ({ path, min }) => (error_messages?.date?.min ?? "").replaceAll("{path}", path).replaceAll("{min}", new Date(min).toISOString()));
104
- if (config.max) schema2 = schema2.max(config.max, ({ path, max }) => (error_messages?.date?.max ?? "").replaceAll("{path}", path).replaceAll("{max}", new Date(max).toISOString()));
149
+ if (config.min) schema2 = schema2.min(config.min, ({ path: path2, min }) => (error_messages?.date?.min ?? "").replaceAll("{path}", path2).replaceAll("{min}", new Date(min).toISOString()));
150
+ if (config.max) schema2 = schema2.max(config.max, ({ path: path2, max }) => (error_messages?.date?.max ?? "").replaceAll("{path}", path2).replaceAll("{max}", new Date(max).toISOString()));
105
151
  return schema2;
106
152
  } else if (config.type === "object") {
107
- schema2 = Yup.object().typeError(({ path }) => (error_messages?.object?.type ?? "").replaceAll("{path}", path));
153
+ schema2 = Yup.object().typeError(({ path: path2 }) => (error_messages?.object?.type ?? "").replaceAll("{path}", path2));
108
154
  schema2 = base(schema2, key, config);
109
155
  const nested_properties = {};
110
156
  for (const [nested_key, nested_config] of Object.entries(config.properties)) nested_properties[nested_key] = build(nested_key, nested_config);
111
157
  schema2 = schema2.shape(nested_properties);
112
158
  return schema2;
113
159
  } else if (config.type === "array") {
114
- schema2 = Yup.array().typeError(({ path }) => (error_messages?.array?.type ?? "").replaceAll("{path}", path));
160
+ schema2 = Yup.array().typeError(({ path: path2 }) => (error_messages?.array?.type ?? "").replaceAll("{path}", path2));
115
161
  schema2 = base(schema2, key, config);
116
162
  if (config.min)
117
163
  schema2 = schema2.min(
118
164
  config.min,
119
- ({ path, min }) => (error_messages?.array?.min ?? "").replaceAll("{path}", path).replaceAll("{min}", min.toString()).replaceAll("{plural_suffix}", min > 1 ? "s" : "")
165
+ ({ path: path2, min }) => (error_messages?.array?.min ?? "").replaceAll("{path}", path2).replaceAll("{min}", min.toString()).replaceAll("{plural_suffix}", min > 1 ? "s" : "")
120
166
  );
121
167
  if (config.max)
122
168
  schema2 = schema2.max(
123
169
  config.max,
124
- ({ path, max }) => (error_messages?.array?.max ?? "").replaceAll("{path}", path).replaceAll("{max}", max.toString()).replaceAll("{plural_suffix}", max > 1 ? "s" : "")
170
+ ({ path: path2, max }) => (error_messages?.array?.max ?? "").replaceAll("{path}", path2).replaceAll("{max}", max.toString()).replaceAll("{plural_suffix}", max > 1 ? "s" : "")
125
171
  );
126
172
  schema2 = schema2.of(build(key, config.items));
127
173
  return schema2;
@@ -132,51 +178,9 @@ var convertToYup = (schema, error_messages) => {
132
178
  return Yup.object().shape(properties);
133
179
  };
134
180
 
135
- // src/utils/ConvertToJSONSchema.util.ts
136
- var import_typebox = require("@sinclair/typebox");
137
- var convertToJSONSchema = (schema) => {
138
- const base = (schema2, key, config) => {
139
- if (!config.required) schema2 = import_typebox.Type.Optional(schema2);
140
- if (config.nullable || config.default === null) schema2 = import_typebox.Type.Union([schema2, import_typebox.Type.Null()]);
141
- return schema2;
142
- };
143
- const build = (key, config) => {
144
- let schema2;
145
- if (config.type === "string") {
146
- schema2 = import_typebox.Type.String({ enum: config.enum, minLength: config.min, maxLength: config.max, pattern: config.pattern ? new RegExp(config.pattern).source : void 0, default: config.default });
147
- schema2 = base(schema2, key, config);
148
- return schema2;
149
- } else if (config.type === "number") {
150
- schema2 = config.integer === true ? import_typebox.Type.Integer({ enum: config.enum, minimum: config.min, maximum: config.max, default: config.default }) : import_typebox.Type.Number({ enum: config.enum, minimum: config.min, maximum: config.max, default: config.default });
151
- schema2 = base(schema2, key, config);
152
- return schema2;
153
- } else if (config.type === "boolean") {
154
- schema2 = import_typebox.Type.Boolean({ default: config.default });
155
- schema2 = base(schema2, key, config);
156
- return schema2;
157
- } else if (config.type === "date") {
158
- schema2 = import_typebox.Type.String({ format: "date-time", minimum: config.min, maximum: config.max, default: config.default });
159
- schema2 = base(schema2, key, config);
160
- return schema2;
161
- } else if (config.type === "object") {
162
- const nested_properties = {};
163
- for (const [nested_key, nested_config] of Object.entries(config.properties)) nested_properties[nested_key] = build(nested_key, nested_config);
164
- schema2 = import_typebox.Type.Object(nested_properties);
165
- schema2 = base(schema2, key, config);
166
- return schema2;
167
- } else if (config.type === "array") {
168
- schema2 = import_typebox.Type.Array(build(key, config.items), { minItems: config.min, maxItems: config.max, default: config.default });
169
- schema2 = base(schema2, key, config);
170
- return schema2;
171
- } else throw new Error(`Unsupported schema type for ${key}`);
172
- };
173
- const properties = {};
174
- for (const [key, config] of Object.entries(schema)) properties[key] = build(key, config);
175
- return import_typebox.Type.Object(properties);
176
- };
177
-
178
181
  // src/defaults/YuppiOptions.default.ts
179
182
  var YuppiOptionsDefault = {
183
+ folder_path: "./",
180
184
  error_messages: {
181
185
  base: {
182
186
  nullable: "Field {path} cannot be null",
@@ -228,14 +232,29 @@ var Yuppi = class {
228
232
  this.options = import_lodash.default.merge({}, YuppiOptionsDefault, options);
229
233
  }
230
234
  validate(schema, properties) {
231
- const yup_schema = convertToYup(schema, this.options.error_messages);
235
+ const yup_schema = this.convertToYup(schema);
232
236
  return yup_schema.validateSync(properties, this.options.validate_options);
233
237
  }
238
+ declare(schema, name) {
239
+ name = name.toLowerCase();
240
+ const types_dir = import_path.default.join(this.options.folder_path ?? "./", "yuppi", "types");
241
+ const banner_comment = `/* eslint-disable */
242
+
243
+ /**
244
+ * This type was automatically generated by **Yuppi**.
245
+ * _DO NOT MODIFY IT BY HAND_. Instead, modify your Yuppi schema.
246
+ * Use \`Yuppi.declare()\` to regenerate this type.
247
+ */`;
248
+ (0, import_json_schema_to_typescript.compile)(this.convertToJSONSchema(schema), name, { bannerComment: banner_comment }).then((type) => {
249
+ import_fs.default.mkdirSync(types_dir, { recursive: true });
250
+ import_fs.default.writeFileSync(import_path.default.join(types_dir, `${name}.d.ts`), type);
251
+ });
252
+ }
234
253
  convertToYup(schema) {
235
254
  return convertToYup(schema, this.options.error_messages);
236
255
  }
237
256
  convertToJSONSchema(schema) {
238
- return convertToJSONSchema(schema);
257
+ return JSON.parse(JSON.stringify(convertToJSONSchema(schema)));
239
258
  }
240
259
  };
241
260
 
package/dist/main.mjs CHANGED
@@ -5,7 +5,53 @@ var __export = (target, all) => {
5
5
  };
6
6
 
7
7
  // src/Yuppi.class.ts
8
+ import { compile } from "json-schema-to-typescript";
8
9
  import _ from "lodash";
10
+ import fs from "fs";
11
+ import path from "path";
12
+
13
+ // src/utils/ConvertToJSONSchema.util.ts
14
+ import { Type } from "@sinclair/typebox";
15
+ var convertToJSONSchema = (schema) => {
16
+ const base = (schema2, key, config) => {
17
+ if (!config.required) schema2 = Type.Optional(schema2);
18
+ if (config.nullable || config.default === null) schema2 = Type.Union([schema2, Type.Null()]);
19
+ return schema2;
20
+ };
21
+ const build = (key, config) => {
22
+ let schema2;
23
+ if (config.type === "string") {
24
+ schema2 = Type.String({ enum: config.enum, minLength: config.min, maxLength: config.max, pattern: config.pattern ? new RegExp(config.pattern).source : void 0, default: config.default });
25
+ schema2 = base(schema2, key, config);
26
+ return schema2;
27
+ } else if (config.type === "number") {
28
+ schema2 = config.integer === true ? Type.Integer({ enum: config.enum, minimum: config.min, maximum: config.max, default: config.default }) : Type.Number({ enum: config.enum, minimum: config.min, maximum: config.max, default: config.default });
29
+ schema2 = base(schema2, key, config);
30
+ return schema2;
31
+ } else if (config.type === "boolean") {
32
+ schema2 = Type.Boolean({ default: config.default });
33
+ schema2 = base(schema2, key, config);
34
+ return schema2;
35
+ } else if (config.type === "date") {
36
+ schema2 = Type.String({ format: "date-time", minimum: config.min, maximum: config.max, default: config.default });
37
+ schema2 = base(schema2, key, config);
38
+ return schema2;
39
+ } else if (config.type === "object") {
40
+ const nested_properties = {};
41
+ for (const [nested_key, nested_config] of Object.entries(config.properties)) nested_properties[nested_key] = build(nested_key, nested_config);
42
+ schema2 = Type.Object(nested_properties, { additionalProperties: false });
43
+ schema2 = base(schema2, key, config);
44
+ return schema2;
45
+ } else if (config.type === "array") {
46
+ schema2 = Type.Array(build(key, config.items), { minItems: config.min, maxItems: config.max, default: config.default });
47
+ schema2 = base(schema2, key, config);
48
+ return schema2;
49
+ } else throw new Error(`Unsupported schema type for ${key}`);
50
+ };
51
+ const properties = {};
52
+ for (const [key, config] of Object.entries(schema)) properties[key] = build(key, config);
53
+ return Type.Object(properties, { additionalProperties: false });
54
+ };
9
55
 
10
56
  // src/utils/ConvertToYup.util.ts
11
57
  import * as Yup from "yup";
@@ -15,7 +61,7 @@ var convertToYup = (schema, error_messages) => {
15
61
  if (config.required)
16
62
  schema2 = schema2.test(
17
63
  "required",
18
- ({ path }) => (error_messages?.base?.required ?? "").replaceAll("{path}", path),
64
+ ({ path: path2 }) => (error_messages?.base?.required ?? "").replaceAll("{path}", path2),
19
65
  (property) => {
20
66
  if (property === void 0) return false;
21
67
  if (typeof property === "string" && property.trim() === "") return false;
@@ -23,74 +69,74 @@ var convertToYup = (schema, error_messages) => {
23
69
  return true;
24
70
  }
25
71
  );
26
- if (!config.nullable && config.default !== null) schema2 = schema2.nonNullable(({ path }) => (error_messages?.base?.nullable ?? "").replaceAll("{path}", path));
72
+ if (!config.nullable && config.default !== null) schema2 = schema2.nonNullable(({ path: path2 }) => (error_messages?.base?.nullable ?? "").replaceAll("{path}", path2));
27
73
  if (config.default) schema2 = schema2.default(config.default);
28
74
  return schema2;
29
75
  };
30
76
  const build = (key, config) => {
31
77
  let schema2;
32
78
  if (config.type === "string") {
33
- schema2 = Yup.string().typeError(({ path }) => (error_messages?.string?.type ?? "").replaceAll("{path}", path));
79
+ schema2 = Yup.string().typeError(({ path: path2 }) => (error_messages?.string?.type ?? "").replaceAll("{path}", path2));
34
80
  schema2 = base(schema2, key, config);
35
81
  schema2 = schema2.transform((property) => typeof property === "string" ? property.trim() : property);
36
82
  if (config.enum)
37
83
  schema2 = schema2.oneOf(
38
84
  config.enum.map((item) => item.trim()),
39
- ({ path }) => (error_messages?.string?.enum ?? "").replaceAll("{path}", path)
85
+ ({ path: path2 }) => (error_messages?.string?.enum ?? "").replaceAll("{path}", path2)
40
86
  );
41
- if (config.pattern) schema2 = schema2.matches(new RegExp(config.pattern), ({ path }) => (error_messages?.string?.pattern ?? "").replaceAll("{path}", path).replaceAll("{pattern}", config.pattern ? new RegExp(config.pattern).source : ""));
87
+ if (config.pattern) schema2 = schema2.matches(new RegExp(config.pattern), ({ path: path2 }) => (error_messages?.string?.pattern ?? "").replaceAll("{path}", path2).replaceAll("{pattern}", config.pattern ? new RegExp(config.pattern).source : ""));
42
88
  if (config.min)
43
89
  schema2 = schema2.min(
44
90
  config.min,
45
- ({ path, min }) => (error_messages?.string?.min ?? "").replaceAll("{path}", path).replaceAll("{min}", min.toString()).replaceAll("{plural_suffix}", min > 1 ? "s" : "")
91
+ ({ path: path2, min }) => (error_messages?.string?.min ?? "").replaceAll("{path}", path2).replaceAll("{min}", min.toString()).replaceAll("{plural_suffix}", min > 1 ? "s" : "")
46
92
  );
47
93
  if (config.max)
48
94
  schema2 = schema2.max(
49
95
  config.max,
50
- ({ path, max }) => (error_messages?.string?.max ?? "").replaceAll("{path}", path).replaceAll("{max}", max.toString()).replaceAll("{plural_suffix}", max > 1 ? "s" : "")
96
+ ({ path: path2, max }) => (error_messages?.string?.max ?? "").replaceAll("{path}", path2).replaceAll("{max}", max.toString()).replaceAll("{plural_suffix}", max > 1 ? "s" : "")
51
97
  );
52
98
  if (config.lowercase) schema2 = schema2.transform((property) => typeof property === "string" ? property.toLowerCase() : property);
53
99
  if (config.uppercase) schema2 = schema2.transform((property) => typeof property === "string" ? property.toUpperCase() : property);
54
100
  return schema2;
55
101
  } else if (config.type === "number") {
56
- schema2 = Yup.number().typeError(({ path }) => (error_messages?.number?.type ?? "").replaceAll("{path}", path));
102
+ schema2 = Yup.number().typeError(({ path: path2 }) => (error_messages?.number?.type ?? "").replaceAll("{path}", path2));
57
103
  schema2 = base(schema2, key, config);
58
- if (config.enum) schema2 = schema2.oneOf(config.enum, ({ path }) => (error_messages?.number?.enum ?? "").replaceAll("{path}", path));
59
- if (config.min) schema2 = schema2.min(config.min, ({ path, min }) => (error_messages?.number?.min ?? "").replaceAll("{path}", path).replaceAll("{min}", min.toString()));
60
- if (config.max) schema2 = schema2.max(config.max, ({ path, max }) => (error_messages?.number?.max ?? "").replaceAll("{path}", path).replaceAll("{max}", max.toString()));
61
- if (config.integer) schema2 = schema2.integer(({ path }) => (error_messages?.number?.integer ?? "").replaceAll("{path}", path));
62
- if (config.positive) schema2 = schema2.positive(({ path }) => (error_messages?.number?.positive ?? "").replaceAll("{path}", path));
63
- if (config.negative) schema2 = schema2.negative(({ path }) => (error_messages?.number?.negative ?? "").replaceAll("{path}", path));
104
+ if (config.enum) schema2 = schema2.oneOf(config.enum, ({ path: path2 }) => (error_messages?.number?.enum ?? "").replaceAll("{path}", path2));
105
+ if (config.min) schema2 = schema2.min(config.min, ({ path: path2, min }) => (error_messages?.number?.min ?? "").replaceAll("{path}", path2).replaceAll("{min}", min.toString()));
106
+ if (config.max) schema2 = schema2.max(config.max, ({ path: path2, max }) => (error_messages?.number?.max ?? "").replaceAll("{path}", path2).replaceAll("{max}", max.toString()));
107
+ if (config.integer) schema2 = schema2.integer(({ path: path2 }) => (error_messages?.number?.integer ?? "").replaceAll("{path}", path2));
108
+ if (config.positive) schema2 = schema2.positive(({ path: path2 }) => (error_messages?.number?.positive ?? "").replaceAll("{path}", path2));
109
+ if (config.negative) schema2 = schema2.negative(({ path: path2 }) => (error_messages?.number?.negative ?? "").replaceAll("{path}", path2));
64
110
  return schema2;
65
111
  } else if (config.type === "boolean") {
66
- schema2 = Yup.boolean().typeError(({ path }) => (error_messages?.boolean?.type ?? "").replaceAll("{path}", path));
112
+ schema2 = Yup.boolean().typeError(({ path: path2 }) => (error_messages?.boolean?.type ?? "").replaceAll("{path}", path2));
67
113
  schema2 = base(schema2, key, config);
68
114
  return schema2;
69
115
  } else if (config.type === "date") {
70
- schema2 = Yup.date().typeError(({ path }) => (error_messages?.date?.type ?? "").replaceAll("{path}", path));
116
+ schema2 = Yup.date().typeError(({ path: path2 }) => (error_messages?.date?.type ?? "").replaceAll("{path}", path2));
71
117
  schema2 = base(schema2, key, config);
72
- if (config.min) schema2 = schema2.min(config.min, ({ path, min }) => (error_messages?.date?.min ?? "").replaceAll("{path}", path).replaceAll("{min}", new Date(min).toISOString()));
73
- if (config.max) schema2 = schema2.max(config.max, ({ path, max }) => (error_messages?.date?.max ?? "").replaceAll("{path}", path).replaceAll("{max}", new Date(max).toISOString()));
118
+ if (config.min) schema2 = schema2.min(config.min, ({ path: path2, min }) => (error_messages?.date?.min ?? "").replaceAll("{path}", path2).replaceAll("{min}", new Date(min).toISOString()));
119
+ if (config.max) schema2 = schema2.max(config.max, ({ path: path2, max }) => (error_messages?.date?.max ?? "").replaceAll("{path}", path2).replaceAll("{max}", new Date(max).toISOString()));
74
120
  return schema2;
75
121
  } else if (config.type === "object") {
76
- schema2 = Yup.object().typeError(({ path }) => (error_messages?.object?.type ?? "").replaceAll("{path}", path));
122
+ schema2 = Yup.object().typeError(({ path: path2 }) => (error_messages?.object?.type ?? "").replaceAll("{path}", path2));
77
123
  schema2 = base(schema2, key, config);
78
124
  const nested_properties = {};
79
125
  for (const [nested_key, nested_config] of Object.entries(config.properties)) nested_properties[nested_key] = build(nested_key, nested_config);
80
126
  schema2 = schema2.shape(nested_properties);
81
127
  return schema2;
82
128
  } else if (config.type === "array") {
83
- schema2 = Yup.array().typeError(({ path }) => (error_messages?.array?.type ?? "").replaceAll("{path}", path));
129
+ schema2 = Yup.array().typeError(({ path: path2 }) => (error_messages?.array?.type ?? "").replaceAll("{path}", path2));
84
130
  schema2 = base(schema2, key, config);
85
131
  if (config.min)
86
132
  schema2 = schema2.min(
87
133
  config.min,
88
- ({ path, min }) => (error_messages?.array?.min ?? "").replaceAll("{path}", path).replaceAll("{min}", min.toString()).replaceAll("{plural_suffix}", min > 1 ? "s" : "")
134
+ ({ path: path2, min }) => (error_messages?.array?.min ?? "").replaceAll("{path}", path2).replaceAll("{min}", min.toString()).replaceAll("{plural_suffix}", min > 1 ? "s" : "")
89
135
  );
90
136
  if (config.max)
91
137
  schema2 = schema2.max(
92
138
  config.max,
93
- ({ path, max }) => (error_messages?.array?.max ?? "").replaceAll("{path}", path).replaceAll("{max}", max.toString()).replaceAll("{plural_suffix}", max > 1 ? "s" : "")
139
+ ({ path: path2, max }) => (error_messages?.array?.max ?? "").replaceAll("{path}", path2).replaceAll("{max}", max.toString()).replaceAll("{plural_suffix}", max > 1 ? "s" : "")
94
140
  );
95
141
  schema2 = schema2.of(build(key, config.items));
96
142
  return schema2;
@@ -101,51 +147,9 @@ var convertToYup = (schema, error_messages) => {
101
147
  return Yup.object().shape(properties);
102
148
  };
103
149
 
104
- // src/utils/ConvertToJSONSchema.util.ts
105
- import { Type } from "@sinclair/typebox";
106
- var convertToJSONSchema = (schema) => {
107
- const base = (schema2, key, config) => {
108
- if (!config.required) schema2 = Type.Optional(schema2);
109
- if (config.nullable || config.default === null) schema2 = Type.Union([schema2, Type.Null()]);
110
- return schema2;
111
- };
112
- const build = (key, config) => {
113
- let schema2;
114
- if (config.type === "string") {
115
- schema2 = Type.String({ enum: config.enum, minLength: config.min, maxLength: config.max, pattern: config.pattern ? new RegExp(config.pattern).source : void 0, default: config.default });
116
- schema2 = base(schema2, key, config);
117
- return schema2;
118
- } else if (config.type === "number") {
119
- schema2 = config.integer === true ? Type.Integer({ enum: config.enum, minimum: config.min, maximum: config.max, default: config.default }) : Type.Number({ enum: config.enum, minimum: config.min, maximum: config.max, default: config.default });
120
- schema2 = base(schema2, key, config);
121
- return schema2;
122
- } else if (config.type === "boolean") {
123
- schema2 = Type.Boolean({ default: config.default });
124
- schema2 = base(schema2, key, config);
125
- return schema2;
126
- } else if (config.type === "date") {
127
- schema2 = Type.String({ format: "date-time", minimum: config.min, maximum: config.max, default: config.default });
128
- schema2 = base(schema2, key, config);
129
- return schema2;
130
- } else if (config.type === "object") {
131
- const nested_properties = {};
132
- for (const [nested_key, nested_config] of Object.entries(config.properties)) nested_properties[nested_key] = build(nested_key, nested_config);
133
- schema2 = Type.Object(nested_properties);
134
- schema2 = base(schema2, key, config);
135
- return schema2;
136
- } else if (config.type === "array") {
137
- schema2 = Type.Array(build(key, config.items), { minItems: config.min, maxItems: config.max, default: config.default });
138
- schema2 = base(schema2, key, config);
139
- return schema2;
140
- } else throw new Error(`Unsupported schema type for ${key}`);
141
- };
142
- const properties = {};
143
- for (const [key, config] of Object.entries(schema)) properties[key] = build(key, config);
144
- return Type.Object(properties);
145
- };
146
-
147
150
  // src/defaults/YuppiOptions.default.ts
148
151
  var YuppiOptionsDefault = {
152
+ folder_path: "./",
149
153
  error_messages: {
150
154
  base: {
151
155
  nullable: "Field {path} cannot be null",
@@ -197,14 +201,29 @@ var Yuppi = class {
197
201
  this.options = _.merge({}, YuppiOptionsDefault, options);
198
202
  }
199
203
  validate(schema, properties) {
200
- const yup_schema = convertToYup(schema, this.options.error_messages);
204
+ const yup_schema = this.convertToYup(schema);
201
205
  return yup_schema.validateSync(properties, this.options.validate_options);
202
206
  }
207
+ declare(schema, name) {
208
+ name = name.toLowerCase();
209
+ const types_dir = path.join(this.options.folder_path ?? "./", "yuppi", "types");
210
+ const banner_comment = `/* eslint-disable */
211
+
212
+ /**
213
+ * This type was automatically generated by **Yuppi**.
214
+ * _DO NOT MODIFY IT BY HAND_. Instead, modify your Yuppi schema.
215
+ * Use \`Yuppi.declare()\` to regenerate this type.
216
+ */`;
217
+ compile(this.convertToJSONSchema(schema), name, { bannerComment: banner_comment }).then((type) => {
218
+ fs.mkdirSync(types_dir, { recursive: true });
219
+ fs.writeFileSync(path.join(types_dir, `${name}.d.ts`), type);
220
+ });
221
+ }
203
222
  convertToYup(schema) {
204
223
  return convertToYup(schema, this.options.error_messages);
205
224
  }
206
225
  convertToJSONSchema(schema) {
207
- return convertToJSONSchema(schema);
226
+ return JSON.parse(JSON.stringify(convertToJSONSchema(schema)));
208
227
  }
209
228
  };
210
229
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yuppi",
3
- "version": "1.2.11",
3
+ "version": "1.3.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",
@@ -17,6 +17,8 @@
17
17
  "dependencies": {
18
18
  "@sinclair/typebox": "^0.34.41",
19
19
  "@types/lodash": "^4.17.20",
20
+ "@types/node": "^24.5.2",
21
+ "json-schema-to-typescript": "^15.0.4",
20
22
  "lodash": "^4.17.21",
21
23
  "yup": "^1.7.1"
22
24
  },
@@ -31,6 +33,7 @@
31
33
  },
32
34
  "keywords": [
33
35
  "validate",
36
+ "validation",
34
37
  "typecheck",
35
38
  "yup",
36
39
  "json-schema",