@railway-ts/pipelines 0.1.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 +811 -0
- package/dist/composition/index.cjs +72 -0
- package/dist/composition/index.cjs.map +1 -0
- package/dist/composition/index.d.cts +286 -0
- package/dist/composition/index.d.ts +286 -0
- package/dist/composition/index.mjs +65 -0
- package/dist/composition/index.mjs.map +1 -0
- package/dist/index-BdfKTZ7O.d.cts +799 -0
- package/dist/index-BdfKTZ7O.d.ts +799 -0
- package/dist/index.cjs +1074 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.mjs +969 -0
- package/dist/index.mjs.map +1 -0
- package/dist/option/index.cjs +111 -0
- package/dist/option/index.cjs.map +1 -0
- package/dist/option/index.d.cts +1 -0
- package/dist/option/index.d.ts +1 -0
- package/dist/option/index.mjs +93 -0
- package/dist/option/index.mjs.map +1 -0
- package/dist/result/index.cjs +178 -0
- package/dist/result/index.cjs.map +1 -0
- package/dist/result/index.d.cts +1 -0
- package/dist/result/index.d.ts +1 -0
- package/dist/result/index.mjs +152 -0
- package/dist/result/index.mjs.map +1 -0
- package/dist/schema/index.cjs +794 -0
- package/dist/schema/index.cjs.map +1 -0
- package/dist/schema/index.d.cts +1867 -0
- package/dist/schema/index.d.ts +1867 -0
- package/dist/schema/index.mjs +735 -0
- package/dist/schema/index.mjs.map +1 -0
- package/examples/complete-pipelines/async-launch.ts +128 -0
- package/examples/complete-pipelines/async.ts +119 -0
- package/examples/complete-pipelines/hill-clohessy-wiltshire.ts +218 -0
- package/examples/complete-pipelines/hohmann-transfer.ts +159 -0
- package/examples/composition/advanced-composition.ts +32 -0
- package/examples/composition/curry-basics.ts +24 -0
- package/examples/composition/tupled-basics.ts +26 -0
- package/examples/index.ts +47 -0
- package/examples/interop/interop-examples.ts +110 -0
- package/examples/option/option-examples.ts +63 -0
- package/examples/result/result-examples.ts +110 -0
- package/examples/schema/basic.ts +78 -0
- package/examples/schema/union.ts +301 -0
- package/package.json +100 -0
|
@@ -0,0 +1,735 @@
|
|
|
1
|
+
// src/result/result.ts
|
|
2
|
+
var RESULT_BRAND = Symbol("RESULT_BRAND");
|
|
3
|
+
function ok(value) {
|
|
4
|
+
return {
|
|
5
|
+
ok: true,
|
|
6
|
+
value,
|
|
7
|
+
[RESULT_BRAND]: "ok"
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
function err(error) {
|
|
11
|
+
return { ok: false, error, [RESULT_BRAND]: "error" };
|
|
12
|
+
}
|
|
13
|
+
function isOk(result) {
|
|
14
|
+
return result.ok;
|
|
15
|
+
}
|
|
16
|
+
function isErr(result) {
|
|
17
|
+
return !result.ok;
|
|
18
|
+
}
|
|
19
|
+
function mapErr(result, fn) {
|
|
20
|
+
return result.ok ? result : err(fn(result.error));
|
|
21
|
+
}
|
|
22
|
+
function match(result, patterns) {
|
|
23
|
+
if (isOk(result)) {
|
|
24
|
+
const okFn = patterns.ok;
|
|
25
|
+
return okFn(result.value);
|
|
26
|
+
} else {
|
|
27
|
+
const errFn = patterns.err;
|
|
28
|
+
return errFn(result.error);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function fromTry(f) {
|
|
32
|
+
try {
|
|
33
|
+
return ok(f());
|
|
34
|
+
} catch (error) {
|
|
35
|
+
return err(error instanceof Error ? error.message : String(error));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// src/schema/core.ts
|
|
40
|
+
function object(schema, { strict = true } = {}) {
|
|
41
|
+
return (obj, parentPath = []) => {
|
|
42
|
+
if (obj === null || typeof obj !== "object") {
|
|
43
|
+
return err([{ path: parentPath, message: "Expected an object" }]);
|
|
44
|
+
}
|
|
45
|
+
const allErrors = [];
|
|
46
|
+
const validatedObj = {};
|
|
47
|
+
if (strict !== false) {
|
|
48
|
+
const extraKeys = Object.keys(obj).filter((key) => !Object.prototype.hasOwnProperty.call(schema, key));
|
|
49
|
+
if (extraKeys.length > 0) {
|
|
50
|
+
for (const key of extraKeys) {
|
|
51
|
+
allErrors.push({
|
|
52
|
+
path: [...parentPath, key],
|
|
53
|
+
message: `Unexpected field: '${key}'`
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
for (const key in schema) {
|
|
59
|
+
if (!Object.prototype.hasOwnProperty.call(schema, key)) continue;
|
|
60
|
+
const validator = schema[key];
|
|
61
|
+
if (!validator) continue;
|
|
62
|
+
const value = obj[key];
|
|
63
|
+
const fieldPath = [...parentPath, key];
|
|
64
|
+
const result = validator(value, fieldPath);
|
|
65
|
+
if (isOk(result)) {
|
|
66
|
+
validatedObj[key] = result.value;
|
|
67
|
+
} else {
|
|
68
|
+
allErrors.push(...result.error);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (allErrors.length > 0) {
|
|
72
|
+
return err(allErrors);
|
|
73
|
+
}
|
|
74
|
+
return ok(validatedObj);
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
function required(validator, message = "Field is required") {
|
|
78
|
+
return (value, path = []) => {
|
|
79
|
+
if (value === void 0 || value === null) {
|
|
80
|
+
return err([{ path, message }]);
|
|
81
|
+
}
|
|
82
|
+
return validator(value, path);
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function optional(validator) {
|
|
86
|
+
return (value, path = []) => {
|
|
87
|
+
if (value === void 0 || value === null) {
|
|
88
|
+
return ok(void 0);
|
|
89
|
+
}
|
|
90
|
+
return validator(value, path);
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function nullable(message = "Must be null") {
|
|
94
|
+
return (value, path = []) => {
|
|
95
|
+
if (value !== null) {
|
|
96
|
+
return err([{ path, message }]);
|
|
97
|
+
}
|
|
98
|
+
return ok(null);
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function emptyAsOptional(validator) {
|
|
102
|
+
return (value, path = []) => {
|
|
103
|
+
if (value === "" || Array.isArray(value) && value.length === 0 || typeof value === "object" && value !== null && Object.keys(value).length === 0) {
|
|
104
|
+
return ok(void 0);
|
|
105
|
+
}
|
|
106
|
+
return optional(validator)(value, path);
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function literal(expectedValue, message = `Value must be '${String(expectedValue)}'`) {
|
|
110
|
+
return (value, path = []) => {
|
|
111
|
+
if (value !== expectedValue) {
|
|
112
|
+
return err([{ path, message }]);
|
|
113
|
+
}
|
|
114
|
+
return ok(expectedValue);
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// src/schema/utils.ts
|
|
119
|
+
function chain(...validators) {
|
|
120
|
+
return (value, path = []) => {
|
|
121
|
+
let result = ok(value);
|
|
122
|
+
for (const validator of validators) {
|
|
123
|
+
if (isErr(result)) return result;
|
|
124
|
+
const nextResult = validator(result.value, path);
|
|
125
|
+
result = isErr(nextResult) ? nextResult : ok(nextResult.value);
|
|
126
|
+
}
|
|
127
|
+
return result;
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
function validate(value, validator, path = []) {
|
|
131
|
+
return validator(value, path);
|
|
132
|
+
}
|
|
133
|
+
function formatErrors(errors) {
|
|
134
|
+
return errors.reduce(
|
|
135
|
+
(acc, error) => {
|
|
136
|
+
const formattedPath = error.path.reduce((path, segment, index) => {
|
|
137
|
+
if (/^\d+$/.test(segment)) {
|
|
138
|
+
return `${path}[${segment}]`;
|
|
139
|
+
} else {
|
|
140
|
+
return index === 0 ? segment : `${path}.${segment}`;
|
|
141
|
+
}
|
|
142
|
+
}, "");
|
|
143
|
+
acc[formattedPath] = error.message;
|
|
144
|
+
return acc;
|
|
145
|
+
},
|
|
146
|
+
{}
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
function validateAndFormatResult(input, schema) {
|
|
150
|
+
const result = validate(input, schema);
|
|
151
|
+
return match(result, {
|
|
152
|
+
ok: (data) => ({ valid: true, data }),
|
|
153
|
+
err: (errors) => ({ valid: false, errors: formatErrors(errors) })
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
function transform(transformer) {
|
|
157
|
+
return (value) => ok(transformer(value));
|
|
158
|
+
}
|
|
159
|
+
function refine(predicate, message = "Custom validation failed") {
|
|
160
|
+
return (value, path = []) => {
|
|
161
|
+
if (!predicate(value)) {
|
|
162
|
+
return err([{ path, message }]);
|
|
163
|
+
}
|
|
164
|
+
return ok(value);
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// src/schema/string.ts
|
|
169
|
+
function string(message = "Must be a string") {
|
|
170
|
+
return (value, path = []) => {
|
|
171
|
+
if (typeof value !== "string") {
|
|
172
|
+
return err([{ path, message }]);
|
|
173
|
+
}
|
|
174
|
+
return ok(value);
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
function minLength(min2, message = `Must be at least ${min2} characters`) {
|
|
178
|
+
return (value, path = []) => {
|
|
179
|
+
if (value.length < min2) {
|
|
180
|
+
return err([{ path, message }]);
|
|
181
|
+
}
|
|
182
|
+
return ok(value);
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
function maxLength(max2, message = `Must be at most ${max2} characters`) {
|
|
186
|
+
return (value, path = []) => {
|
|
187
|
+
if (value.length > max2) {
|
|
188
|
+
return err([{ path, message }]);
|
|
189
|
+
}
|
|
190
|
+
return ok(value);
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
function pattern(regex, message = "Invalid format") {
|
|
194
|
+
return (value, path = []) => {
|
|
195
|
+
if (!regex.test(value)) {
|
|
196
|
+
return err([{ path, message }]);
|
|
197
|
+
}
|
|
198
|
+
return ok(value);
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
function nonEmpty(message = "String must not be empty") {
|
|
202
|
+
return (value, path = []) => {
|
|
203
|
+
if (value.trim().length === 0) {
|
|
204
|
+
return err([{ path, message }]);
|
|
205
|
+
}
|
|
206
|
+
return ok(value);
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
function email(message = "Invalid email format") {
|
|
210
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
211
|
+
return pattern(emailRegex, message);
|
|
212
|
+
}
|
|
213
|
+
function phoneNumber(message = "Invalid phone number format") {
|
|
214
|
+
const phoneRegex = /^\+?[\d\s\-()]{8,20}$/;
|
|
215
|
+
return (value, path = []) => {
|
|
216
|
+
const cleanedValue = value.replaceAll(/\s+/g, "");
|
|
217
|
+
if (!phoneRegex.test(cleanedValue)) {
|
|
218
|
+
return err([{ path, message }]);
|
|
219
|
+
}
|
|
220
|
+
return ok(value);
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// src/schema/array.ts
|
|
225
|
+
function array(itemValidator) {
|
|
226
|
+
return (value, parentPath = []) => {
|
|
227
|
+
if (!Array.isArray(value)) {
|
|
228
|
+
return err([{ path: parentPath, message: "Expected an array" }]);
|
|
229
|
+
}
|
|
230
|
+
const allErrors = [];
|
|
231
|
+
const validatedItems = [];
|
|
232
|
+
for (const [i, item] of value.entries()) {
|
|
233
|
+
const itemPath = [...parentPath, i.toString()];
|
|
234
|
+
const result = itemValidator(item, itemPath);
|
|
235
|
+
if (isOk(result)) {
|
|
236
|
+
validatedItems.push(result.value);
|
|
237
|
+
} else {
|
|
238
|
+
allErrors.push(...result.error);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
if (allErrors.length > 0) {
|
|
242
|
+
return err(allErrors);
|
|
243
|
+
}
|
|
244
|
+
return ok(validatedItems);
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
function minItems(min2, message = `Array must have at least ${min2} items`) {
|
|
248
|
+
return (value, path = []) => {
|
|
249
|
+
if (value.length < min2) {
|
|
250
|
+
return err([{ path, message }]);
|
|
251
|
+
}
|
|
252
|
+
return ok(value);
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
function maxItems(max2, message = `Array must have at most ${max2} items`) {
|
|
256
|
+
return (value, path = []) => {
|
|
257
|
+
if (value.length > max2) {
|
|
258
|
+
return err([{ path, message }]);
|
|
259
|
+
}
|
|
260
|
+
return ok(value);
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
function notEmpty(message = "Array must not be empty") {
|
|
264
|
+
return minItems(1, message);
|
|
265
|
+
}
|
|
266
|
+
function unique(message = "Array must contain unique values", keyExtractor) {
|
|
267
|
+
return (value, path = []) => {
|
|
268
|
+
const seen = /* @__PURE__ */ new Set();
|
|
269
|
+
for (const [i, item] of value.entries()) {
|
|
270
|
+
const key = keyExtractor ? keyExtractor(item) : item;
|
|
271
|
+
if (seen.has(key)) {
|
|
272
|
+
return err([
|
|
273
|
+
{
|
|
274
|
+
path: [...path, i.toString()],
|
|
275
|
+
message
|
|
276
|
+
}
|
|
277
|
+
]);
|
|
278
|
+
}
|
|
279
|
+
seen.add(key);
|
|
280
|
+
}
|
|
281
|
+
return ok(value);
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
function oneOf(allowedValues, message = `Value must be one of: ${allowedValues.join(", ")}`) {
|
|
285
|
+
return (value, path = []) => {
|
|
286
|
+
if (!allowedValues.includes(value)) {
|
|
287
|
+
return err([{ path, message }]);
|
|
288
|
+
}
|
|
289
|
+
return ok(value);
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
function stringEnum(allowedValues, message = `Value must be one of: ${allowedValues.join(", ")}`) {
|
|
293
|
+
return chain(string("Value must be a string"), (value, path = []) => {
|
|
294
|
+
if (!allowedValues.includes(value)) {
|
|
295
|
+
return err([{ path, message }]);
|
|
296
|
+
}
|
|
297
|
+
return ok(value);
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// src/schema/number.ts
|
|
302
|
+
function number(message = "Must be a number") {
|
|
303
|
+
return (value, path = []) => {
|
|
304
|
+
if (typeof value !== "number" || Number.isNaN(value)) {
|
|
305
|
+
return err([{ path, message }]);
|
|
306
|
+
}
|
|
307
|
+
return ok(value);
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
function min(value, message = `Must be at least ${value}`) {
|
|
311
|
+
return (input, path = []) => {
|
|
312
|
+
if (input < value) {
|
|
313
|
+
return err([{ path, message }]);
|
|
314
|
+
}
|
|
315
|
+
return ok(input);
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
function max(value, message = `Must be at most ${value}`) {
|
|
319
|
+
return (input, path = []) => {
|
|
320
|
+
if (input > value) {
|
|
321
|
+
return err([{ path, message }]);
|
|
322
|
+
}
|
|
323
|
+
return ok(input);
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
function between(min2, max2, message = `Must be between ${min2} and ${max2}`) {
|
|
327
|
+
return (input, path = []) => {
|
|
328
|
+
if (input < min2 || input > max2) {
|
|
329
|
+
return err([{ path, message }]);
|
|
330
|
+
}
|
|
331
|
+
return ok(input);
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
function integer(message = "Must be an integer") {
|
|
335
|
+
return (value, path = []) => {
|
|
336
|
+
if (!Number.isInteger(value)) {
|
|
337
|
+
return err([{ path, message }]);
|
|
338
|
+
}
|
|
339
|
+
return ok(value);
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
function positive(message = "Must be a positive number") {
|
|
343
|
+
return (value, path = []) => {
|
|
344
|
+
if (value <= 0) {
|
|
345
|
+
return err([{ path, message }]);
|
|
346
|
+
}
|
|
347
|
+
return ok(value);
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
function negative(message = "Must be a negative number") {
|
|
351
|
+
return (value, path = []) => {
|
|
352
|
+
if (value >= 0) {
|
|
353
|
+
return err([{ path, message }]);
|
|
354
|
+
}
|
|
355
|
+
return ok(value);
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
function nonZero(message = "Must not be zero") {
|
|
359
|
+
return (value, path = []) => {
|
|
360
|
+
if (value === 0) {
|
|
361
|
+
return err([{ path, message }]);
|
|
362
|
+
}
|
|
363
|
+
return ok(value);
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
function divisibleBy(divisor, message = `Must be divisible by ${divisor}`) {
|
|
367
|
+
return (value, path = []) => {
|
|
368
|
+
if (value % divisor !== 0) {
|
|
369
|
+
return err([{ path, message }]);
|
|
370
|
+
}
|
|
371
|
+
return ok(value);
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
function precision(maxDecimalPlaces, message = `Must have at most ${maxDecimalPlaces} decimal places`) {
|
|
375
|
+
return (value, path = []) => {
|
|
376
|
+
const str = value.toString();
|
|
377
|
+
const decimalPlaces = (str.split(".")[1] || "").length;
|
|
378
|
+
if (decimalPlaces > maxDecimalPlaces) {
|
|
379
|
+
return err([{ path, message }]);
|
|
380
|
+
}
|
|
381
|
+
return ok(value);
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
function finite(message = "Must be a finite number") {
|
|
385
|
+
return (value, path = []) => {
|
|
386
|
+
if (!Number.isFinite(value)) {
|
|
387
|
+
return err([{ path, message }]);
|
|
388
|
+
}
|
|
389
|
+
return ok(value);
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// src/schema/parsers.ts
|
|
394
|
+
function parseNumber(message = "Must be a valid number") {
|
|
395
|
+
return (value, path = []) => {
|
|
396
|
+
if (typeof value === "number") {
|
|
397
|
+
return ok(value);
|
|
398
|
+
}
|
|
399
|
+
if (typeof value === "string") {
|
|
400
|
+
const trimmed = value.trim();
|
|
401
|
+
if (trimmed === "") {
|
|
402
|
+
return err([{ path, message }]);
|
|
403
|
+
}
|
|
404
|
+
const num = Number(trimmed);
|
|
405
|
+
if (!Number.isNaN(num)) {
|
|
406
|
+
return ok(num);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
return err([{ path, message }]);
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
function parseBigInt(message = "Must be a valid BigInt") {
|
|
413
|
+
return (value, path = []) => {
|
|
414
|
+
if (typeof value === "bigint") {
|
|
415
|
+
return ok(value);
|
|
416
|
+
}
|
|
417
|
+
if (typeof value === "string" || typeof value === "number") {
|
|
418
|
+
try {
|
|
419
|
+
if (typeof value === "number" && !Number.isInteger(value)) {
|
|
420
|
+
return err([
|
|
421
|
+
{
|
|
422
|
+
path,
|
|
423
|
+
message: "Cannot convert non-integer number to BigInt"
|
|
424
|
+
}
|
|
425
|
+
]);
|
|
426
|
+
}
|
|
427
|
+
const bigIntValue = BigInt(value);
|
|
428
|
+
return ok(bigIntValue);
|
|
429
|
+
} catch {
|
|
430
|
+
return err([{ path, message }]);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
return err([{ path, message }]);
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
function parseEnum(enumObject, message = `Must be a valid enum value`) {
|
|
437
|
+
return (value, path = []) => {
|
|
438
|
+
const enumEntries = Object.entries(enumObject).filter(
|
|
439
|
+
([key]) => Number.isNaN(Number(key)) || !Number.isInteger(Number(key))
|
|
440
|
+
);
|
|
441
|
+
const enumValues = enumEntries.map(([, val]) => val);
|
|
442
|
+
if (enumValues.includes(value)) {
|
|
443
|
+
return ok(value);
|
|
444
|
+
}
|
|
445
|
+
if (typeof value === "string") {
|
|
446
|
+
const parsed = Number(value);
|
|
447
|
+
if (!Number.isNaN(parsed) && enumValues.includes(parsed)) {
|
|
448
|
+
return ok(parsed);
|
|
449
|
+
}
|
|
450
|
+
const exactEntry = enumEntries.find(([key]) => key === value);
|
|
451
|
+
if (exactEntry) {
|
|
452
|
+
return ok(exactEntry[1]);
|
|
453
|
+
}
|
|
454
|
+
const lowerValue = value.toLowerCase();
|
|
455
|
+
const caseInsensitiveEntry = enumEntries.find(([key]) => key.toLowerCase() === lowerValue);
|
|
456
|
+
if (caseInsensitiveEntry) {
|
|
457
|
+
return ok(caseInsensitiveEntry[1]);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
return err([
|
|
461
|
+
{
|
|
462
|
+
path,
|
|
463
|
+
message
|
|
464
|
+
}
|
|
465
|
+
]);
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
function parseDate(message = "Must be a valid date") {
|
|
469
|
+
return (value, path = []) => {
|
|
470
|
+
if (value instanceof Date) {
|
|
471
|
+
return ok(value);
|
|
472
|
+
}
|
|
473
|
+
let dateValue;
|
|
474
|
+
if (typeof value === "string") {
|
|
475
|
+
dateValue = new Date(value);
|
|
476
|
+
} else if (typeof value === "number") {
|
|
477
|
+
dateValue = new Date(value);
|
|
478
|
+
} else {
|
|
479
|
+
return err([{ path, message }]);
|
|
480
|
+
}
|
|
481
|
+
if (Number.isNaN(dateValue.getTime())) {
|
|
482
|
+
return err([{ path, message }]);
|
|
483
|
+
}
|
|
484
|
+
return ok(dateValue);
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
function parseBool(message = "Must be a valid boolean value") {
|
|
488
|
+
return (value, path = []) => {
|
|
489
|
+
if (typeof value === "boolean") {
|
|
490
|
+
return ok(value);
|
|
491
|
+
}
|
|
492
|
+
if (typeof value === "string") {
|
|
493
|
+
const normalized = value.toLowerCase().trim();
|
|
494
|
+
if (normalized === "true" || normalized === "1" || normalized === "yes") {
|
|
495
|
+
return ok(true);
|
|
496
|
+
}
|
|
497
|
+
if (normalized === "false" || normalized === "0" || normalized === "no") {
|
|
498
|
+
return ok(false);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
if (typeof value === "number") {
|
|
502
|
+
if (value === 1) return ok(true);
|
|
503
|
+
if (value === 0) return ok(false);
|
|
504
|
+
}
|
|
505
|
+
return err([{ path, message }]);
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
function parseString(message = "Must be convertible to string") {
|
|
509
|
+
return (value, path = []) => {
|
|
510
|
+
if (typeof value === "string") {
|
|
511
|
+
return ok(value);
|
|
512
|
+
}
|
|
513
|
+
if (value === null || value === void 0) {
|
|
514
|
+
return err([{ path, message }]);
|
|
515
|
+
}
|
|
516
|
+
return ok(String(value));
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
function parseJSON(message = "Must be valid JSON") {
|
|
520
|
+
return (value, path = []) => {
|
|
521
|
+
if (typeof value === "string") {
|
|
522
|
+
return mapErr(
|
|
523
|
+
fromTry(() => JSON.parse(value)),
|
|
524
|
+
() => [{ path, message }]
|
|
525
|
+
);
|
|
526
|
+
}
|
|
527
|
+
if (typeof value === "object" && value !== null) {
|
|
528
|
+
return ok(value);
|
|
529
|
+
}
|
|
530
|
+
return err([{ path, message }]);
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
function parseISODate(message = "Must be a valid ISO date string") {
|
|
534
|
+
return (value, path = []) => {
|
|
535
|
+
if (typeof value !== "string") {
|
|
536
|
+
return err([{ path, message }]);
|
|
537
|
+
}
|
|
538
|
+
if (!/^\d{4}-\d{2}-\d{2}/.test(value)) {
|
|
539
|
+
return err([{ path, message }]);
|
|
540
|
+
}
|
|
541
|
+
const date2 = new Date(value);
|
|
542
|
+
if (Number.isNaN(date2.getTime())) {
|
|
543
|
+
return err([{ path, message }]);
|
|
544
|
+
}
|
|
545
|
+
const originalMonth = value.slice(5, 7);
|
|
546
|
+
const originalDay = value.slice(8, 10);
|
|
547
|
+
const parsedMonth = String(date2.getUTCMonth() + 1).padStart(2, "0");
|
|
548
|
+
const parsedDay = String(date2.getUTCDate()).padStart(2, "0");
|
|
549
|
+
if (originalMonth !== parsedMonth || originalDay !== parsedDay) {
|
|
550
|
+
return err([{ path, message }]);
|
|
551
|
+
}
|
|
552
|
+
return ok(date2);
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
function parseURL(message = "Must be a valid URL") {
|
|
556
|
+
return (value, path = []) => {
|
|
557
|
+
if (typeof value !== "string") {
|
|
558
|
+
return err([{ path, message }]);
|
|
559
|
+
}
|
|
560
|
+
try {
|
|
561
|
+
return ok(new URL(value));
|
|
562
|
+
} catch {
|
|
563
|
+
return err([{ path, message }]);
|
|
564
|
+
}
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
// src/schema/date.ts
|
|
569
|
+
function date(message = "Must be a Date object") {
|
|
570
|
+
return (value, path = []) => {
|
|
571
|
+
if (!(value instanceof Date)) {
|
|
572
|
+
return err([{ path, message }]);
|
|
573
|
+
}
|
|
574
|
+
if (Number.isNaN(value.getTime())) {
|
|
575
|
+
return err([
|
|
576
|
+
{
|
|
577
|
+
path,
|
|
578
|
+
message: "Invalid Date"
|
|
579
|
+
}
|
|
580
|
+
]);
|
|
581
|
+
}
|
|
582
|
+
return ok(value);
|
|
583
|
+
};
|
|
584
|
+
}
|
|
585
|
+
function dateRange(min2, max2, message = `Must be between ${min2.toISOString().split("T")[0]} and ${max2.toISOString().split("T")[0]}`) {
|
|
586
|
+
return (value, path = []) => {
|
|
587
|
+
if (value < min2 || value > max2) {
|
|
588
|
+
return err([{ path, message }]);
|
|
589
|
+
}
|
|
590
|
+
return ok(value);
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
function pastDate(message = "Must be a date in the past") {
|
|
594
|
+
return (value, path = []) => {
|
|
595
|
+
if (value >= /* @__PURE__ */ new Date()) {
|
|
596
|
+
return err([{ path, message }]);
|
|
597
|
+
}
|
|
598
|
+
return ok(value);
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
function futureDate(message = "Must be a date in the future") {
|
|
602
|
+
return (value, path = []) => {
|
|
603
|
+
if (value <= /* @__PURE__ */ new Date()) {
|
|
604
|
+
return err([{ path, message }]);
|
|
605
|
+
}
|
|
606
|
+
return ok(value);
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
function todayOrFuture(message = "Must be today or a future date") {
|
|
610
|
+
const today = /* @__PURE__ */ new Date();
|
|
611
|
+
today.setHours(0, 0, 0, 0);
|
|
612
|
+
return (value, path = []) => {
|
|
613
|
+
if (value < today) {
|
|
614
|
+
return err([{ path, message }]);
|
|
615
|
+
}
|
|
616
|
+
return ok(value);
|
|
617
|
+
};
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
// src/schema/boolean.ts
|
|
621
|
+
function boolean(message = "Must be a boolean") {
|
|
622
|
+
return (value, path = []) => {
|
|
623
|
+
if (typeof value !== "boolean") {
|
|
624
|
+
return err([{ path, message }]);
|
|
625
|
+
}
|
|
626
|
+
return ok(value);
|
|
627
|
+
};
|
|
628
|
+
}
|
|
629
|
+
function matches(expected, message = `Value must be ${expected}`) {
|
|
630
|
+
return (value, path = []) => {
|
|
631
|
+
if (value !== expected) {
|
|
632
|
+
return err([{ path, message }]);
|
|
633
|
+
}
|
|
634
|
+
return ok(value);
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
// src/schema/union.ts
|
|
639
|
+
function union(validators, options) {
|
|
640
|
+
const { collectAllErrors = true, errorPrefix } = options || {};
|
|
641
|
+
return (value, parentPath = []) => {
|
|
642
|
+
if (validators.length === 0) {
|
|
643
|
+
return err([{ path: parentPath, message: "No validators provided to union" }]);
|
|
644
|
+
}
|
|
645
|
+
const allErrors = [];
|
|
646
|
+
for (const validator of validators) {
|
|
647
|
+
const result = validator(value, parentPath);
|
|
648
|
+
if (isOk(result)) {
|
|
649
|
+
return result;
|
|
650
|
+
}
|
|
651
|
+
allErrors.push(result.error);
|
|
652
|
+
if (!collectAllErrors) {
|
|
653
|
+
break;
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
const combinedErrors = allErrors.flat().map((error) => ({
|
|
657
|
+
path: error.path,
|
|
658
|
+
message: errorPrefix ? `${errorPrefix}: ${error.message}` : error.message
|
|
659
|
+
}));
|
|
660
|
+
return err(combinedErrors);
|
|
661
|
+
};
|
|
662
|
+
}
|
|
663
|
+
function discriminatedUnion(discriminantField, validatorMap, fallbackMessage = `Invalid discriminant value for '${discriminantField}'`) {
|
|
664
|
+
return (value, parentPath = []) => {
|
|
665
|
+
if (value === null || typeof value !== "object") {
|
|
666
|
+
return err([{ path: parentPath, message: "Expected an object" }]);
|
|
667
|
+
}
|
|
668
|
+
const discriminantValue = value[discriminantField];
|
|
669
|
+
if (typeof discriminantValue !== "string") {
|
|
670
|
+
return err([
|
|
671
|
+
{
|
|
672
|
+
path: [...parentPath, discriminantField],
|
|
673
|
+
message: `Missing or invalid discriminant field '${discriminantField}'`
|
|
674
|
+
}
|
|
675
|
+
]);
|
|
676
|
+
}
|
|
677
|
+
const validator = validatorMap[discriminantValue];
|
|
678
|
+
if (!validator) {
|
|
679
|
+
return err([
|
|
680
|
+
{
|
|
681
|
+
path: [...parentPath, discriminantField],
|
|
682
|
+
message: `${fallbackMessage}: '${discriminantValue}'`
|
|
683
|
+
}
|
|
684
|
+
]);
|
|
685
|
+
}
|
|
686
|
+
return validator(value, parentPath);
|
|
687
|
+
};
|
|
688
|
+
}
|
|
689
|
+
function withCommonFields(commonSchema, specificSchema) {
|
|
690
|
+
return (value, path = []) => {
|
|
691
|
+
const commonResult = commonSchema(value, path);
|
|
692
|
+
if (isErr(commonResult)) {
|
|
693
|
+
return commonResult;
|
|
694
|
+
}
|
|
695
|
+
const specificResult = specificSchema(value, path);
|
|
696
|
+
if (isErr(specificResult)) {
|
|
697
|
+
return specificResult;
|
|
698
|
+
}
|
|
699
|
+
const combinedValue = {
|
|
700
|
+
...commonResult.value,
|
|
701
|
+
...specificResult.value
|
|
702
|
+
};
|
|
703
|
+
return ok(combinedValue);
|
|
704
|
+
};
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
// src/schema/enum.ts
|
|
708
|
+
function enumValue(enumObject, message, excludedValues) {
|
|
709
|
+
return (value, path = []) => {
|
|
710
|
+
const enumValues = Object.values(enumObject);
|
|
711
|
+
if (!enumValues.includes(value)) {
|
|
712
|
+
const defaultMessage = `Value must be one of: ${enumValues.join(", ")}`;
|
|
713
|
+
return err([{ path, message: message || defaultMessage }]);
|
|
714
|
+
}
|
|
715
|
+
if (excludedValues && excludedValues.includes(value)) {
|
|
716
|
+
const defaultMessage = `Selected value is excluded from valid enum values`;
|
|
717
|
+
return err([{ path, message: `${message || defaultMessage}` }]);
|
|
718
|
+
}
|
|
719
|
+
return ok(value);
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
// src/schema/bigint.ts
|
|
724
|
+
function bigint(message = "Must be a bigint") {
|
|
725
|
+
return (value, path = []) => {
|
|
726
|
+
if (typeof value !== "bigint") {
|
|
727
|
+
return err([{ path, message }]);
|
|
728
|
+
}
|
|
729
|
+
return ok(value);
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
export { array, between, bigint, boolean, chain, date, dateRange, discriminatedUnion, divisibleBy, email, emptyAsOptional, enumValue, finite, formatErrors, futureDate, integer, literal, matches, max, maxItems, maxLength, min, minItems, minLength, negative, nonEmpty, nonZero, notEmpty, nullable, number, object, oneOf, optional, parseBigInt, parseBool, parseDate, parseEnum, parseISODate, parseJSON, parseNumber, parseString, parseURL, pastDate, pattern, phoneNumber, positive, precision, refine, required, string, stringEnum, todayOrFuture, transform, union, unique, validate, validateAndFormatResult, withCommonFields };
|
|
734
|
+
//# sourceMappingURL=index.mjs.map
|
|
735
|
+
//# sourceMappingURL=index.mjs.map
|