yuppi 1.2.12 → 1.3.1

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,6 +99,7 @@ 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
 
@@ -209,6 +210,36 @@ Validate the properties with your Yuppi schema.
209
210
 
210
211
  <br/>
211
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
+
212
243
  `Yuppi.convertToYup(schema)`
213
244
 
214
245
  Convert your Yuppi schema into Yup schema.
@@ -222,33 +253,6 @@ Convert your Yuppi schema into Yup schema.
222
253
  > Example:
223
254
  >
224
255
  > ```typescript
225
- > const schema: Schema = {
226
- > display_name: {
227
- > type: 'string',
228
- > min: 1,
229
- > max: 32,
230
- > nullable: false,
231
- > required: true
232
- > },
233
- >
234
- > username: {
235
- > type: 'string',
236
- > min: 3,
237
- > max: 16,
238
- > pattern: Patterns.Username,
239
- > nullable: false,
240
- > required: true
241
- > },
242
- >
243
- > email: {
244
- > type: 'string',
245
- > pattern: Patterns.Email,
246
- > lowercase: true,
247
- > nullable: false,
248
- > required: true
249
- > }
250
- > };
251
- >
252
256
  > Yupp.convertToYup(schema);
253
257
  > ```
254
258
 
@@ -267,33 +271,6 @@ Convert your Yuppi schema into [JSON Schema](https://json-schema.org).
267
271
  > Example:
268
272
  >
269
273
  > ```typescript
270
- > const schema: Schema = {
271
- > display_name: {
272
- > type: 'string',
273
- > min: 1,
274
- > max: 32,
275
- > nullable: false,
276
- > required: true
277
- > },
278
- >
279
- > username: {
280
- > type: 'string',
281
- > min: 3,
282
- > max: 16,
283
- > pattern: Patterns.Username,
284
- > nullable: false,
285
- > required: true
286
- > },
287
- >
288
- > email: {
289
- > type: 'string',
290
- > pattern: Patterns.Email,
291
- > lowercase: true,
292
- > nullable: false,
293
- > required: true
294
- > }
295
- > };
296
- >
297
274
  > Yupp.convertToJSONSchema(schema);
298
275
  > /*
299
276
  > {
@@ -319,7 +296,8 @@ Convert your Yuppi schema into [JSON Schema](https://json-schema.org).
319
296
  > "display_name",
320
297
  > "username",
321
298
  > "email"
322
- > ]
299
+ > ],
300
+ > additionalProperties: false
323
301
  > }
324
302
  > */
325
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,14 @@ 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);
181
+ // src/utils/PascalCase.util.ts
182
+ var pascalCase = (text) => {
183
+ return text.replace(/[^a-zA-Z0-9]/g, " ").split(" ").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
176
184
  };
177
185
 
178
186
  // src/defaults/YuppiOptions.default.ts
179
187
  var YuppiOptionsDefault = {
188
+ folder_path: "./",
180
189
  error_messages: {
181
190
  base: {
182
191
  nullable: "Field {path} cannot be null",
@@ -228,14 +237,29 @@ var Yuppi = class {
228
237
  this.options = import_lodash.default.merge({}, YuppiOptionsDefault, options);
229
238
  }
230
239
  validate(schema, properties) {
231
- const yup_schema = convertToYup(schema, this.options.error_messages);
240
+ const yup_schema = this.convertToYup(schema);
232
241
  return yup_schema.validateSync(properties, this.options.validate_options);
233
242
  }
243
+ declare(schema, name) {
244
+ name = pascalCase(name);
245
+ const types_dir = import_path.default.join(this.options.folder_path ?? "./", "yuppi", "types");
246
+ const banner_comment = `/* eslint-disable */
247
+
248
+ /**
249
+ * This type was automatically generated by **Yuppi**.
250
+ * _DO NOT MODIFY IT BY HAND_. Instead, modify your Yuppi schema.
251
+ * Use \`Yuppi.declare()\` to regenerate this type.
252
+ */`;
253
+ (0, import_json_schema_to_typescript.compile)(this.convertToJSONSchema(schema), name, { bannerComment: banner_comment }).then((type) => {
254
+ import_fs.default.mkdirSync(types_dir, { recursive: true });
255
+ import_fs.default.writeFileSync(import_path.default.join(types_dir, `${name}.d.ts`), type);
256
+ });
257
+ }
234
258
  convertToYup(schema) {
235
259
  return convertToYup(schema, this.options.error_messages);
236
260
  }
237
261
  convertToJSONSchema(schema) {
238
- return convertToJSONSchema(schema);
262
+ return JSON.parse(JSON.stringify(convertToJSONSchema(schema)));
239
263
  }
240
264
  };
241
265
 
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,14 @@ 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);
150
+ // src/utils/PascalCase.util.ts
151
+ var pascalCase = (text) => {
152
+ return text.replace(/[^a-zA-Z0-9]/g, " ").split(" ").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
145
153
  };
146
154
 
147
155
  // src/defaults/YuppiOptions.default.ts
148
156
  var YuppiOptionsDefault = {
157
+ folder_path: "./",
149
158
  error_messages: {
150
159
  base: {
151
160
  nullable: "Field {path} cannot be null",
@@ -197,14 +206,29 @@ var Yuppi = class {
197
206
  this.options = _.merge({}, YuppiOptionsDefault, options);
198
207
  }
199
208
  validate(schema, properties) {
200
- const yup_schema = convertToYup(schema, this.options.error_messages);
209
+ const yup_schema = this.convertToYup(schema);
201
210
  return yup_schema.validateSync(properties, this.options.validate_options);
202
211
  }
212
+ declare(schema, name) {
213
+ name = pascalCase(name);
214
+ const types_dir = path.join(this.options.folder_path ?? "./", "yuppi", "types");
215
+ const banner_comment = `/* eslint-disable */
216
+
217
+ /**
218
+ * This type was automatically generated by **Yuppi**.
219
+ * _DO NOT MODIFY IT BY HAND_. Instead, modify your Yuppi schema.
220
+ * Use \`Yuppi.declare()\` to regenerate this type.
221
+ */`;
222
+ compile(this.convertToJSONSchema(schema), name, { bannerComment: banner_comment }).then((type) => {
223
+ fs.mkdirSync(types_dir, { recursive: true });
224
+ fs.writeFileSync(path.join(types_dir, `${name}.d.ts`), type);
225
+ });
226
+ }
203
227
  convertToYup(schema) {
204
228
  return convertToYup(schema, this.options.error_messages);
205
229
  }
206
230
  convertToJSONSchema(schema) {
207
- return convertToJSONSchema(schema);
231
+ return JSON.parse(JSON.stringify(convertToJSONSchema(schema)));
208
232
  }
209
233
  };
210
234
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yuppi",
3
- "version": "1.2.12",
3
+ "version": "1.3.1",
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
  },