@oxog/vld 2.1.0 → 2.2.5
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/CHANGELOG.md +87 -0
- package/README.md +1296 -1235
- package/dist/chunks/errors-core-Cqi4-9ew.js +1 -0
- package/dist/chunks/index-CkbfQQ4n.js +1 -0
- package/dist/chunks/index-yjpbvFgw.js +1 -0
- package/dist/chunks/ip-validation-g5LWgy9t.js +1 -0
- package/dist/chunks/security-Dy24T8N7.js +1 -0
- package/dist/cjs/chunks/errors-core-DKPohm9I.cjs +1 -0
- package/dist/cjs/chunks/index-BEV9nG0N.cjs +1 -0
- package/dist/cjs/chunks/index-ZjHAxYdA.cjs +1 -0
- package/dist/cjs/chunks/ip-validation-BZqPamPC.cjs +1 -0
- package/dist/cjs/chunks/security-aXZVI7qW.cjs +1 -0
- package/dist/cjs/cli/bin.cjs +1 -505
- package/dist/cjs/cli/index.cjs +1 -209
- package/dist/cjs/codecs/index.cjs +1 -45
- package/dist/cjs/coercion/index.cjs +1 -588
- package/dist/cjs/compat/emitter.cjs +1 -184
- package/dist/cjs/compat/result.cjs +1 -189
- package/dist/cjs/errors.cjs +1 -180
- package/dist/cjs/index.cjs +1 -1894
- package/dist/cjs/kernel.cjs +1 -415
- package/dist/cjs/locales/af.cjs +1 -108
- package/dist/cjs/locales/ar.cjs +1 -108
- package/dist/cjs/locales/bn.cjs +1 -108
- package/dist/cjs/locales/da.cjs +1 -108
- package/dist/cjs/locales/de.cjs +1 -108
- package/dist/cjs/locales/en.cjs +1 -108
- package/dist/cjs/locales/es-MX.cjs +1 -107
- package/dist/cjs/locales/es.cjs +1 -96
- package/dist/cjs/locales/fi.cjs +1 -108
- package/dist/cjs/locales/fr.cjs +1 -96
- package/dist/cjs/locales/hi.cjs +1 -108
- package/dist/cjs/locales/id.cjs +1 -108
- package/dist/cjs/locales/index.cjs +1 -43
- package/dist/cjs/locales/it.cjs +1 -108
- package/dist/cjs/locales/ja.cjs +1 -108
- package/dist/cjs/locales/ko.cjs +1 -108
- package/dist/cjs/locales/lazy.cjs +1 -188
- package/dist/cjs/locales/nl.cjs +1 -108
- package/dist/cjs/locales/no.cjs +1 -108
- package/dist/cjs/locales/pl.cjs +1 -108
- package/dist/cjs/locales/pt-BR.cjs +1 -108
- package/dist/cjs/locales/pt.cjs +1 -108
- package/dist/cjs/locales/ru.cjs +1 -108
- package/dist/cjs/locales/runtime.cjs +1 -51
- package/dist/cjs/locales/sv.cjs +1 -108
- package/dist/cjs/locales/sw.cjs +1 -108
- package/dist/cjs/locales/th.cjs +1 -108
- package/dist/cjs/locales/tr.cjs +1 -108
- package/dist/cjs/locales/vi.cjs +1 -108
- package/dist/cjs/locales/zh.cjs +1 -108
- package/dist/cjs/mini.cjs +1 -242
- package/dist/cjs/pigment.cjs +1 -207
- package/dist/cjs/plugins/index.cjs +1 -12
- package/dist/cjs/registry.cjs +1 -37
- package/dist/cjs/v3/index.cjs +1 -425
- package/dist/cjs/v4/core/index.cjs +1 -894
- package/dist/cjs/v4/index.cjs +1 -425
- package/dist/cjs/v4/locales/index.cjs +1 -130
- package/dist/cjs/v4/mini/index.cjs +1 -509
- package/dist/cjs/v4-mini/index.cjs +1 -532
- package/dist/cjs/validators/any.cjs +1 -40
- package/dist/cjs/validators/array.cjs +1 -283
- package/dist/cjs/validators/base.cjs +1 -887
- package/dist/cjs/validators/base64.cjs +1 -73
- package/dist/cjs/validators/bigint.cjs +1 -232
- package/dist/cjs/validators/boolean.cjs +1 -146
- package/dist/cjs/validators/codec.cjs +1 -205
- package/dist/cjs/validators/custom.cjs +1 -71
- package/dist/cjs/validators/date.cjs +1 -278
- package/dist/cjs/validators/discriminated-union.cjs +1 -130
- package/dist/cjs/validators/enum.cjs +1 -154
- package/dist/cjs/validators/file.cjs +1 -130
- package/dist/cjs/validators/function.cjs +1 -63
- package/dist/cjs/validators/hex.cjs +1 -70
- package/dist/cjs/validators/index.cjs +1 -123
- package/dist/cjs/validators/intersection.cjs +1 -120
- package/dist/cjs/validators/json.cjs +1 -70
- package/dist/cjs/validators/lazy.cjs +1 -53
- package/dist/cjs/validators/literal.cjs +1 -64
- package/dist/cjs/validators/map.cjs +1 -218
- package/dist/cjs/validators/nan.cjs +1 -41
- package/dist/cjs/validators/never.cjs +1 -36
- package/dist/cjs/validators/null.cjs +1 -43
- package/dist/cjs/validators/number.cjs +1 -427
- package/dist/cjs/validators/object.cjs +1 -868
- package/dist/cjs/validators/promise.cjs +1 -115
- package/dist/cjs/validators/record.cjs +1 -262
- package/dist/cjs/validators/set.cjs +1 -203
- package/dist/cjs/validators/string-bool.cjs +1 -124
- package/dist/cjs/validators/string-formats.cjs +1 -168
- package/dist/cjs/validators/string.cjs +1 -12
- package/dist/cjs/validators/symbol.cjs +1 -62
- package/dist/cjs/validators/template-literal.cjs +1 -108
- package/dist/cjs/validators/tuple.cjs +1 -187
- package/dist/cjs/validators/uint8array.cjs +1 -106
- package/dist/cjs/validators/undefined.cjs +1 -43
- package/dist/cjs/validators/union.cjs +1 -191
- package/dist/cjs/validators/unknown.cjs +1 -40
- package/dist/cjs/validators/void.cjs +1 -48
- package/dist/cjs/validators/xor.cjs +1 -69
- package/dist/cli/bin.js +1 -406
- package/dist/cli/index.js +1 -205
- package/dist/codecs/index.js +1 -11
- package/dist/coercion/index.js +1 -579
- package/dist/compat/emitter.js +1 -180
- package/dist/compat/result.js +1 -170
- package/dist/errors-core.d.ts +20 -1
- package/dist/errors.js +1 -171
- package/dist/index.d.ts +248 -357
- package/dist/index.js +1 -1534
- package/dist/kernel.js +1 -409
- package/dist/locales/af.js +1 -106
- package/dist/locales/ar.js +1 -106
- package/dist/locales/bn.js +1 -106
- package/dist/locales/da.js +1 -106
- package/dist/locales/de.js +1 -106
- package/dist/locales/en.js +1 -106
- package/dist/locales/es-MX.js +1 -105
- package/dist/locales/es.js +1 -94
- package/dist/locales/fi.js +1 -106
- package/dist/locales/fr.js +1 -94
- package/dist/locales/hi.js +1 -106
- package/dist/locales/id.js +1 -106
- package/dist/locales/index.js +1 -29
- package/dist/locales/it.js +1 -106
- package/dist/locales/ja.js +1 -106
- package/dist/locales/ko.js +1 -106
- package/dist/locales/lazy.js +1 -177
- package/dist/locales/nl.js +1 -106
- package/dist/locales/no.js +1 -106
- package/dist/locales/pl.js +1 -106
- package/dist/locales/pt-BR.js +1 -106
- package/dist/locales/pt.js +1 -106
- package/dist/locales/ru.js +1 -106
- package/dist/locales/runtime.js +1 -41
- package/dist/locales/sv.js +1 -106
- package/dist/locales/sw.js +1 -106
- package/dist/locales/th.js +1 -106
- package/dist/locales/tr.js +1 -106
- package/dist/locales/vi.js +1 -106
- package/dist/locales/zh.js +1 -106
- package/dist/mini.d.ts +3 -3
- package/dist/mini.js +1 -156
- package/dist/pigment.js +1 -180
- package/dist/plugins/index.js +1 -1
- package/dist/registry.js +1 -34
- package/dist/utils/json-schema.d.ts +10 -1
- package/dist/v3/index.js +1 -46
- package/dist/v4/core/index.d.ts +28 -16
- package/dist/v4/core/index.js +1 -277
- package/dist/v4/index.js +1 -50
- package/dist/v4/locales/index.d.ts +4 -0
- package/dist/v4/locales/index.js +1 -77
- package/dist/v4/mini/index.js +1 -47
- package/dist/v4-mini/index.d.ts +1 -1
- package/dist/v4-mini/index.js +1 -75
- package/dist/validators/any.js +1 -37
- package/dist/validators/array.d.ts +7 -0
- package/dist/validators/array.js +1 -279
- package/dist/validators/base.d.ts +63 -8
- package/dist/validators/base.js +1 -868
- package/dist/validators/base64.js +1 -68
- package/dist/validators/bigint.js +1 -228
- package/dist/validators/boolean.js +1 -142
- package/dist/validators/codec.js +1 -200
- package/dist/validators/custom.js +1 -67
- package/dist/validators/date.js +1 -274
- package/dist/validators/discriminated-union.d.ts +2 -2
- package/dist/validators/discriminated-union.js +1 -123
- package/dist/validators/enum.js +1 -150
- package/dist/validators/file.js +1 -125
- package/dist/validators/function.js +1 -58
- package/dist/validators/hex.js +1 -65
- package/dist/validators/index.d.ts +1 -1
- package/dist/validators/index.js +1 -35
- package/dist/validators/intersection.js +1 -116
- package/dist/validators/json.js +1 -66
- package/dist/validators/lazy.js +1 -50
- package/dist/validators/literal.d.ts +7 -3
- package/dist/validators/literal.js +1 -60
- package/dist/validators/map.js +1 -214
- package/dist/validators/nan.js +1 -38
- package/dist/validators/never.js +1 -32
- package/dist/validators/null.js +1 -40
- package/dist/validators/number.d.ts +20 -1
- package/dist/validators/number.js +1 -423
- package/dist/validators/object.d.ts +12 -2
- package/dist/validators/object.js +1 -864
- package/dist/validators/promise.js +1 -111
- package/dist/validators/record.d.ts +11 -8
- package/dist/validators/record.js +1 -258
- package/dist/validators/set.js +1 -199
- package/dist/validators/string-bool.js +1 -120
- package/dist/validators/string-formats.d.ts +58 -62
- package/dist/validators/string-formats.js +1 -135
- package/dist/validators/string.d.ts +47 -10
- package/dist/validators/string.js +1 -4
- package/dist/validators/symbol.js +1 -58
- package/dist/validators/template-literal.js +1 -103
- package/dist/validators/tuple.d.ts +17 -13
- package/dist/validators/tuple.js +1 -183
- package/dist/validators/uint8array.js +1 -101
- package/dist/validators/undefined.js +1 -40
- package/dist/validators/union.js +1 -187
- package/dist/validators/unknown.js +1 -37
- package/dist/validators/void.js +1 -44
- package/dist/validators/xor.d.ts +2 -2
- package/dist/validators/xor.js +1 -66
- package/package.json +239 -238
- package/dist/chunks/errors-core-BeiFUtZM.js +0 -81
- package/dist/chunks/index-0R2ntSud.js +0 -508
- package/dist/chunks/index-BvH403Yy.js +0 -88
- package/dist/chunks/security-B0Pd_vSY.js +0 -35
- package/dist/chunks/string-BJRQod3t.js +0 -530
- package/dist/cjs/chunks/errors-core-DWxLFs2f.cjs +0 -83
- package/dist/cjs/chunks/index-BkI37108.cjs +0 -538
- package/dist/cjs/chunks/index-Cc3bjUMX.cjs +0 -91
- package/dist/cjs/chunks/security-Dc3Jh13T.cjs +0 -37
- package/dist/cjs/chunks/string-BKZrc4hs.cjs +0 -533
|
@@ -1,69 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
var validators_base = require('./base.cjs');
|
|
4
|
-
require('../registry.cjs');
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* VldXor - Exclusive union validator
|
|
8
|
-
* Part of Zod 4 API parity implementation
|
|
9
|
-
* Ensures exactly one schema in the union matches
|
|
10
|
-
*/
|
|
11
|
-
/**
|
|
12
|
-
* XOR validator - ensures exactly one option matches
|
|
13
|
-
* Unlike regular union which allows multiple matches, XOR requires exactly one
|
|
14
|
-
*/
|
|
15
|
-
class VldXor extends validators_base.VldBase {
|
|
16
|
-
constructor(_options) {
|
|
17
|
-
super(validators_base.VLD_VALIDATOR_TYPES.XOR);
|
|
18
|
-
this._options = _options;
|
|
19
|
-
}
|
|
20
|
-
static create(options) {
|
|
21
|
-
if (options.length < 2) {
|
|
22
|
-
throw new Error('XOR requires at least 2 options');
|
|
23
|
-
}
|
|
24
|
-
return new VldXor(options);
|
|
25
|
-
}
|
|
26
|
-
parse(value) {
|
|
27
|
-
const result = this.safeParse(value);
|
|
28
|
-
if (!result.success) {
|
|
29
|
-
throw result.error;
|
|
30
|
-
}
|
|
31
|
-
return result.data;
|
|
32
|
-
}
|
|
33
|
-
safeParse(value) {
|
|
34
|
-
let matchCount = 0;
|
|
35
|
-
let lastSuccess = null;
|
|
36
|
-
for (const option of this._options) {
|
|
37
|
-
const result = option.safeParse(value);
|
|
38
|
-
if (result.success) {
|
|
39
|
-
matchCount++;
|
|
40
|
-
lastSuccess = result;
|
|
41
|
-
if (matchCount > 1) {
|
|
42
|
-
// Early exit if more than one match
|
|
43
|
-
break;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
if (matchCount === 0) {
|
|
48
|
-
return {
|
|
49
|
-
success: false,
|
|
50
|
-
error: new Error('No schema matched in XOR union')
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
if (matchCount > 1) {
|
|
54
|
-
return {
|
|
55
|
-
success: false,
|
|
56
|
-
error: new Error(`Input matches ${matchCount} schemas in XOR union, but exactly one is required`)
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
return lastSuccess;
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Get all options
|
|
63
|
-
*/
|
|
64
|
-
getOptions() {
|
|
65
|
-
return this._options;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
exports.VldXor = VldXor;
|
|
1
|
+
"use strict";var r=require("./base.cjs");require("../registry.cjs");class VldXor extends r.VldBase{constructor(s){super(r.VLD_VALIDATOR_TYPES.XOR),this._options=s}static create(r){return new VldXor(r)}parse(r){const s=this.safeParse(r);if(!s.success)throw s.error;return s.data}safeParse(r){let s=0,e=null;for(const t of this._options){const o=t.safeParse(r);if(o.success&&(s++,e=o,s>1))break}return 0===s?{success:!1,error:new Error("No schema matched in XOR union")}:s>1?{success:!1,error:new Error(`Input matches ${s} schemas in XOR union, but exactly one is required`)}:e}getOptions(){return this._options}}exports.VldXor=VldXor;
|
package/dist/cli/bin.js
CHANGED
|
@@ -1,407 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import * as fs from 'fs';
|
|
4
|
-
import { readFileSync } from 'fs';
|
|
5
|
-
import * as path from 'path';
|
|
6
|
-
import pigment from '../pigment.js';
|
|
7
|
-
import { prettifyError, prettifyErrorColored } from '../errors.js';
|
|
8
|
-
import v from '../index.js';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* VLD CLI - Validate Command
|
|
12
|
-
*
|
|
13
|
-
* Validate JSON data against a VLD schema file.
|
|
14
|
-
*/
|
|
15
|
-
function assertWithinCwd(absolutePath, label, original) {
|
|
16
|
-
const allowedDir = process.cwd();
|
|
17
|
-
if (!absolutePath.startsWith(allowedDir + path.sep) && absolutePath !== allowedDir) {
|
|
18
|
-
throw new Error(`${label} path escapes allowed directory: ${original}`);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Validate command
|
|
23
|
-
*/
|
|
24
|
-
const validateCommand = {
|
|
25
|
-
name: 'validate',
|
|
26
|
-
description: 'Validate JSON data against a VLD schema',
|
|
27
|
-
aliases: ['v'],
|
|
28
|
-
arguments: [
|
|
29
|
-
{
|
|
30
|
-
name: 'schema',
|
|
31
|
-
description: 'Path to schema file (.ts or .js)',
|
|
32
|
-
required: true
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
name: 'data',
|
|
36
|
-
description: 'Path to JSON data file or JSON string',
|
|
37
|
-
required: true
|
|
38
|
-
}
|
|
39
|
-
],
|
|
40
|
-
options: [
|
|
41
|
-
{
|
|
42
|
-
name: 'strict',
|
|
43
|
-
short: 's',
|
|
44
|
-
description: 'Enable strict mode (no extra keys)',
|
|
45
|
-
type: 'boolean',
|
|
46
|
-
default: false
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
name: 'quiet',
|
|
50
|
-
short: 'q',
|
|
51
|
-
description: 'Only output errors',
|
|
52
|
-
type: 'boolean',
|
|
53
|
-
default: false
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
name: 'json',
|
|
57
|
-
short: 'j',
|
|
58
|
-
description: 'Output as JSON',
|
|
59
|
-
type: 'boolean',
|
|
60
|
-
default: false
|
|
61
|
-
},
|
|
62
|
-
{
|
|
63
|
-
name: 'no-color',
|
|
64
|
-
description: 'Disable colored output',
|
|
65
|
-
type: 'boolean',
|
|
66
|
-
default: false
|
|
67
|
-
}
|
|
68
|
-
],
|
|
69
|
-
action: async (args, options) => {
|
|
70
|
-
const schemaPath = args['schema'];
|
|
71
|
-
const dataArg = args['data'];
|
|
72
|
-
const quiet = options['quiet'];
|
|
73
|
-
const json = options['json'];
|
|
74
|
-
const noColor = options['no-color'];
|
|
75
|
-
// Load schema
|
|
76
|
-
let schema;
|
|
77
|
-
try {
|
|
78
|
-
const absoluteSchemaPath = path.resolve(process.cwd(), schemaPath);
|
|
79
|
-
// Security: Ensure resolved path is within allowed directories
|
|
80
|
-
assertWithinCwd(absoluteSchemaPath, 'Schema', schemaPath);
|
|
81
|
-
if (!fs.existsSync(absoluteSchemaPath)) {
|
|
82
|
-
throw new Error(`Schema file not found: ${schemaPath}`);
|
|
83
|
-
}
|
|
84
|
-
// Dynamic import for ESM/CJS compatibility
|
|
85
|
-
const schemaModule = await import(absoluteSchemaPath);
|
|
86
|
-
schema = schemaModule.default || schemaModule.schema || schemaModule;
|
|
87
|
-
if (!schema || typeof schema.parse !== 'function') {
|
|
88
|
-
throw new Error('Schema must export a VLD validator with parse() method');
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
catch (error) {
|
|
92
|
-
if (json) {
|
|
93
|
-
console.log(JSON.stringify({ success: false, error: error.message }));
|
|
94
|
-
}
|
|
95
|
-
else {
|
|
96
|
-
console.error(pigment.red('Schema Error:'), error.message);
|
|
97
|
-
}
|
|
98
|
-
process.exitCode = 1;
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
// Load data
|
|
102
|
-
let data;
|
|
103
|
-
try {
|
|
104
|
-
// Check if it's a file path or JSON string
|
|
105
|
-
if (dataArg.startsWith('{') || dataArg.startsWith('[')) {
|
|
106
|
-
data = JSON.parse(dataArg);
|
|
107
|
-
}
|
|
108
|
-
else {
|
|
109
|
-
const absoluteDataPath = path.resolve(process.cwd(), dataArg);
|
|
110
|
-
// Security: Ensure resolved path is within allowed directories
|
|
111
|
-
assertWithinCwd(absoluteDataPath, 'Data', dataArg);
|
|
112
|
-
if (!fs.existsSync(absoluteDataPath)) {
|
|
113
|
-
throw new Error(`Data file not found: ${dataArg}`);
|
|
114
|
-
}
|
|
115
|
-
const content = fs.readFileSync(absoluteDataPath, 'utf-8');
|
|
116
|
-
data = JSON.parse(content);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
catch (error) {
|
|
120
|
-
if (json) {
|
|
121
|
-
console.log(JSON.stringify({ success: false, error: error.message }));
|
|
122
|
-
}
|
|
123
|
-
else {
|
|
124
|
-
console.error(pigment.red('Data Error:'), error.message);
|
|
125
|
-
}
|
|
126
|
-
process.exitCode = 1;
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
// Validate
|
|
130
|
-
const result = schema.safeParse(data);
|
|
131
|
-
if (json) {
|
|
132
|
-
if (result.success) {
|
|
133
|
-
console.log(JSON.stringify({ success: true, data: result.data }));
|
|
134
|
-
}
|
|
135
|
-
else {
|
|
136
|
-
const err = result.error;
|
|
137
|
-
const errorJson = {
|
|
138
|
-
success: false,
|
|
139
|
-
error: err?.message,
|
|
140
|
-
issues: err?.issues
|
|
141
|
-
};
|
|
142
|
-
console.log(JSON.stringify(errorJson));
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
else {
|
|
146
|
-
if (result.success) {
|
|
147
|
-
if (!quiet) {
|
|
148
|
-
console.log(pigment.green('Validation passed'));
|
|
149
|
-
console.log('');
|
|
150
|
-
console.log(pigment.dim('Data:'));
|
|
151
|
-
console.log(JSON.stringify(result.data, null, 2));
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
else {
|
|
155
|
-
console.error(pigment.red('Validation failed'));
|
|
156
|
-
console.error('');
|
|
157
|
-
// Check if it's a VldError with issues
|
|
158
|
-
if (result.error && 'issues' in result.error) {
|
|
159
|
-
const formatted = noColor
|
|
160
|
-
? prettifyError(result.error, { colored: false })
|
|
161
|
-
: prettifyErrorColored(result.error);
|
|
162
|
-
console.error(formatted);
|
|
163
|
-
}
|
|
164
|
-
else {
|
|
165
|
-
console.error(result.error?.message || 'Unknown error');
|
|
166
|
-
}
|
|
167
|
-
process.exitCode = 1;
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* VLD CLI - Benchmark Command
|
|
175
|
-
*
|
|
176
|
-
* Run performance benchmarks for VLD validation.
|
|
177
|
-
*/
|
|
178
|
-
/**
|
|
179
|
-
* Run a single benchmark
|
|
180
|
-
*/
|
|
181
|
-
function runBenchmark(name, fn, iterations) {
|
|
182
|
-
// Warm up
|
|
183
|
-
for (let i = 0; i < Math.min(100, iterations / 10); i++) {
|
|
184
|
-
fn();
|
|
185
|
-
}
|
|
186
|
-
// Run benchmark
|
|
187
|
-
const start = performance.now();
|
|
188
|
-
for (let i = 0; i < iterations; i++) {
|
|
189
|
-
fn();
|
|
190
|
-
}
|
|
191
|
-
const end = performance.now();
|
|
192
|
-
const totalMs = end - start;
|
|
193
|
-
const avgMs = totalMs / iterations;
|
|
194
|
-
const opsPerSec = 1000 / avgMs;
|
|
195
|
-
return { name, iterations, totalMs, avgMs, opsPerSec };
|
|
196
|
-
}
|
|
197
|
-
/**
|
|
198
|
-
* Format number with comma separators
|
|
199
|
-
*/
|
|
200
|
-
function formatNumber(n) {
|
|
201
|
-
return n.toLocaleString('en-US', { maximumFractionDigits: 2 });
|
|
202
|
-
}
|
|
203
|
-
/**
|
|
204
|
-
* Format benchmark result
|
|
205
|
-
*/
|
|
206
|
-
function formatResult(result, colored) {
|
|
207
|
-
const name = colored ? pigment.cyan(result.name.padEnd(30)) : result.name.padEnd(30);
|
|
208
|
-
const ops = colored
|
|
209
|
-
? pigment.green(formatNumber(result.opsPerSec).padStart(12))
|
|
210
|
-
: formatNumber(result.opsPerSec).padStart(12);
|
|
211
|
-
const avg = colored
|
|
212
|
-
? pigment.yellow(result.avgMs.toFixed(6).padStart(12))
|
|
213
|
-
: result.avgMs.toFixed(6).padStart(12);
|
|
214
|
-
return `${name} ${ops} ops/sec ${avg} ms/op`;
|
|
215
|
-
}
|
|
216
|
-
/**
|
|
217
|
-
* Benchmark command
|
|
218
|
-
*/
|
|
219
|
-
const benchmarkCommand = {
|
|
220
|
-
name: 'benchmark',
|
|
221
|
-
description: 'Run performance benchmarks',
|
|
222
|
-
aliases: ['bench', 'b'],
|
|
223
|
-
options: [
|
|
224
|
-
{
|
|
225
|
-
name: 'iterations',
|
|
226
|
-
short: 'n',
|
|
227
|
-
description: 'Number of iterations',
|
|
228
|
-
type: 'number',
|
|
229
|
-
default: 10000
|
|
230
|
-
},
|
|
231
|
-
{
|
|
232
|
-
name: 'suite',
|
|
233
|
-
short: 's',
|
|
234
|
-
description: 'Benchmark suite to run (all, primitives, objects, arrays)',
|
|
235
|
-
type: 'string',
|
|
236
|
-
default: 'all'
|
|
237
|
-
},
|
|
238
|
-
{
|
|
239
|
-
name: 'json',
|
|
240
|
-
short: 'j',
|
|
241
|
-
description: 'Output as JSON',
|
|
242
|
-
type: 'boolean',
|
|
243
|
-
default: false
|
|
244
|
-
},
|
|
245
|
-
{
|
|
246
|
-
name: 'no-color',
|
|
247
|
-
description: 'Disable colored output',
|
|
248
|
-
type: 'boolean',
|
|
249
|
-
default: false
|
|
250
|
-
}
|
|
251
|
-
],
|
|
252
|
-
action: async (_args, options) => {
|
|
253
|
-
const iterations = options['iterations'];
|
|
254
|
-
const suite = options['suite'];
|
|
255
|
-
const json = options['json'];
|
|
256
|
-
const noColor = options['no-color'];
|
|
257
|
-
const colored = !noColor;
|
|
258
|
-
const results = [];
|
|
259
|
-
// Primitive validators
|
|
260
|
-
const stringSchema = v.string();
|
|
261
|
-
const numberSchema = v.number();
|
|
262
|
-
const booleanSchema = v.boolean();
|
|
263
|
-
const dateSchema = v.date();
|
|
264
|
-
// Object validator
|
|
265
|
-
const userSchema = v.object({
|
|
266
|
-
name: v.string(),
|
|
267
|
-
email: v.string(),
|
|
268
|
-
age: v.number(),
|
|
269
|
-
active: v.boolean()
|
|
270
|
-
});
|
|
271
|
-
// Array validator
|
|
272
|
-
const numbersSchema = v.array(v.number());
|
|
273
|
-
// Nested object validator
|
|
274
|
-
const nestedSchema = v.object({
|
|
275
|
-
user: v.object({
|
|
276
|
-
name: v.string(),
|
|
277
|
-
email: v.string()
|
|
278
|
-
}),
|
|
279
|
-
items: v.array(v.object({
|
|
280
|
-
id: v.number(),
|
|
281
|
-
name: v.string(),
|
|
282
|
-
price: v.number()
|
|
283
|
-
}))
|
|
284
|
-
});
|
|
285
|
-
// Test data
|
|
286
|
-
const testString = 'hello world';
|
|
287
|
-
const testNumber = 42;
|
|
288
|
-
const testBoolean = true;
|
|
289
|
-
const testDate = new Date();
|
|
290
|
-
const testUser = { name: 'John', email: 'john@example.com', age: 30, active: true };
|
|
291
|
-
const testNumbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
|
292
|
-
const testNested = {
|
|
293
|
-
user: { name: 'John', email: 'john@example.com' },
|
|
294
|
-
items: [
|
|
295
|
-
{ id: 1, name: 'Item 1', price: 10.99 },
|
|
296
|
-
{ id: 2, name: 'Item 2', price: 20.99 },
|
|
297
|
-
{ id: 3, name: 'Item 3', price: 30.99 }
|
|
298
|
-
]
|
|
299
|
-
};
|
|
300
|
-
if (!json) {
|
|
301
|
-
console.log(pigment.bold('VLD Performance Benchmark'));
|
|
302
|
-
console.log(pigment.dim(`Running ${formatNumber(iterations)} iterations per test`));
|
|
303
|
-
console.log('');
|
|
304
|
-
}
|
|
305
|
-
// Primitive benchmarks
|
|
306
|
-
if (suite === 'all' || suite === 'primitives') {
|
|
307
|
-
if (!json) {
|
|
308
|
-
console.log(pigment.bold('Primitives:'));
|
|
309
|
-
}
|
|
310
|
-
results.push(runBenchmark('string.parse()', () => stringSchema.parse(testString), iterations));
|
|
311
|
-
results.push(runBenchmark('number.parse()', () => numberSchema.parse(testNumber), iterations));
|
|
312
|
-
results.push(runBenchmark('boolean.parse()', () => booleanSchema.parse(testBoolean), iterations));
|
|
313
|
-
results.push(runBenchmark('date.parse()', () => dateSchema.parse(testDate), iterations));
|
|
314
|
-
results.push(runBenchmark('string.safeParse()', () => stringSchema.safeParse(testString), iterations));
|
|
315
|
-
if (!json) {
|
|
316
|
-
for (const result of results.slice(-5)) {
|
|
317
|
-
console.log(' ' + formatResult(result, colored));
|
|
318
|
-
}
|
|
319
|
-
console.log('');
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
// Object benchmarks
|
|
323
|
-
if (suite === 'all' || suite === 'objects') {
|
|
324
|
-
if (!json) {
|
|
325
|
-
console.log(pigment.bold('Objects:'));
|
|
326
|
-
}
|
|
327
|
-
results.push(runBenchmark('object.parse()', () => userSchema.parse(testUser), iterations));
|
|
328
|
-
results.push(runBenchmark('object.safeParse()', () => userSchema.safeParse(testUser), iterations));
|
|
329
|
-
results.push(runBenchmark('nested.parse()', () => nestedSchema.parse(testNested), iterations));
|
|
330
|
-
if (!json) {
|
|
331
|
-
for (const result of results.slice(-3)) {
|
|
332
|
-
console.log(' ' + formatResult(result, colored));
|
|
333
|
-
}
|
|
334
|
-
console.log('');
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
// Array benchmarks
|
|
338
|
-
if (suite === 'all' || suite === 'arrays') {
|
|
339
|
-
if (!json) {
|
|
340
|
-
console.log(pigment.bold('Arrays:'));
|
|
341
|
-
}
|
|
342
|
-
results.push(runBenchmark('array.parse()', () => numbersSchema.parse(testNumbers), iterations));
|
|
343
|
-
results.push(runBenchmark('array.safeParse()', () => numbersSchema.safeParse(testNumbers), iterations));
|
|
344
|
-
if (!json) {
|
|
345
|
-
for (const result of results.slice(-2)) {
|
|
346
|
-
console.log(' ' + formatResult(result, colored));
|
|
347
|
-
}
|
|
348
|
-
console.log('');
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
// Summary
|
|
352
|
-
if (!json) {
|
|
353
|
-
const totalOps = results.reduce((sum, r) => sum + r.opsPerSec, 0);
|
|
354
|
-
const avgOps = totalOps / results.length;
|
|
355
|
-
console.log(pigment.bold('Summary:'));
|
|
356
|
-
console.log(` Total benchmarks: ${results.length}`);
|
|
357
|
-
console.log(` Average ops/sec: ${formatNumber(avgOps)}`);
|
|
358
|
-
}
|
|
359
|
-
else {
|
|
360
|
-
console.log(JSON.stringify({
|
|
361
|
-
iterations,
|
|
362
|
-
suite,
|
|
363
|
-
results: results.map((r) => ({
|
|
364
|
-
name: r.name,
|
|
365
|
-
iterations: r.iterations,
|
|
366
|
-
totalMs: r.totalMs,
|
|
367
|
-
avgMs: r.avgMs,
|
|
368
|
-
opsPerSec: r.opsPerSec
|
|
369
|
-
}))
|
|
370
|
-
}));
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
};
|
|
374
|
-
|
|
375
|
-
/**
|
|
376
|
-
* VLD CLI Entry Point
|
|
377
|
-
*
|
|
378
|
-
* This is the main entry point for the `vld` command-line tool.
|
|
379
|
-
*/
|
|
380
|
-
const packageJson = JSON.parse(readFileSync(new URL('../../package.json', import.meta.url), 'utf-8'));
|
|
381
|
-
const version = packageJson.version || '0.0.0';
|
|
382
|
-
vldCli.version = version;
|
|
383
|
-
// Register commands
|
|
384
|
-
vldCli.command(validateCommand);
|
|
385
|
-
vldCli.command(benchmarkCommand);
|
|
386
|
-
// Help command
|
|
387
|
-
vldCli.command({
|
|
388
|
-
name: 'help',
|
|
389
|
-
description: 'Show help information',
|
|
390
|
-
aliases: ['h'],
|
|
391
|
-
action: () => {
|
|
392
|
-
console.log(vldCli.help());
|
|
393
|
-
}
|
|
394
|
-
});
|
|
395
|
-
// Version command
|
|
396
|
-
vldCli.command({
|
|
397
|
-
name: 'version',
|
|
398
|
-
description: 'Show version information',
|
|
399
|
-
action: () => {
|
|
400
|
-
console.log(`vld v${version}`);
|
|
401
|
-
}
|
|
402
|
-
});
|
|
403
|
-
// Run CLI
|
|
404
|
-
vldCli.run(process.argv.slice(2)).catch((error) => {
|
|
405
|
-
console.error('Fatal error:', error);
|
|
406
|
-
process.exitCode = 1;
|
|
407
|
-
});
|
|
2
|
+
import{vldCli as e}from"./index.js";import*as o from"fs";import{readFileSync as s}from"fs";import*as r from"path";import a from"../pigment.js";import{prettifyError as t,prettifyErrorColored as n}from"../errors.js";import i from"../index.js";function c(e,o,s){const a=process.cwd();if(!e.startsWith(a+r.sep)&&e!==a)throw new Error(`${o} path escapes allowed directory: ${s}`)}const l={name:"validate",description:"Validate JSON data against a VLD schema",aliases:["v"],arguments:[{name:"schema",description:"Path to schema file (.ts or .js)",required:!0},{name:"data",description:"Path to JSON data file or JSON string",required:!0}],options:[{name:"strict",short:"s",description:"Enable strict mode (no extra keys)",type:"boolean",default:!1},{name:"quiet",short:"q",description:"Only output errors",type:"boolean",default:!1},{name:"json",short:"j",description:"Output as JSON",type:"boolean",default:!1},{name:"no-color",description:"Disable colored output",type:"boolean",default:!1}],action:async(e,s)=>{const i=e.schema,l=e.data,m=s.quiet,p=s.json,d=s["no-color"];let u,f;try{const e=r.resolve(process.cwd(),i);if(c(e,"Schema",i),!o.existsSync(e))throw new Error(`Schema file not found: ${i}`);const s=await(import(e));if(u=s.default||s.schema||s,!u||"function"!=typeof u.parse)throw new Error("Schema must export a VLD validator with parse() method")}catch(e){return p?console.log(JSON.stringify({success:!1,error:e.message})):console.error(a.red("Schema Error:"),e.message),void(process.exitCode=1)}try{if(l.startsWith("{")||l.startsWith("["))f=JSON.parse(l);else{const e=r.resolve(process.cwd(),l);if(c(e,"Data",l),!o.existsSync(e))throw new Error(`Data file not found: ${l}`);const s=o.readFileSync(e,"utf-8");f=JSON.parse(s)}}catch(e){return p?console.log(JSON.stringify({success:!1,error:e.message})):console.error(a.red("Data Error:"),e.message),void(process.exitCode=1)}const g=u.safeParse(f);if(p)if(g.success)console.log(JSON.stringify({success:!0,data:g.data}));else{const e=g.error,o={success:!1,error:e?.message,issues:e?.issues};console.log(JSON.stringify(o))}else if(g.success)m||(console.log(a.green("Validation passed")),console.log(""),console.log(a.dim("Data:")),console.log(JSON.stringify(g.data,null,2)));else{if(console.error(a.red("Validation failed")),console.error(""),g.error&&"issues"in g.error){const e=d?t(g.error,{colored:!1}):n(g.error);console.error(e)}else console.error(g.error?.message||"Unknown error");process.exitCode=1}}};function m(e,o,s){for(let e=0;e<Math.min(100,s/10);e++)o();const r=performance.now();for(let e=0;e<s;e++)o();const a=performance.now()-r,t=a/s;return{name:e,iterations:s,totalMs:a,avgMs:t,opsPerSec:1e3/t}}function p(e){return e.toLocaleString("en-US",{maximumFractionDigits:2})}function d(e,o){return`${o?a.cyan(e.name.padEnd(30)):e.name.padEnd(30)} ${o?a.green(p(e.opsPerSec).padStart(12)):p(e.opsPerSec).padStart(12)} ops/sec ${o?a.yellow(e.avgMs.toFixed(6).padStart(12)):e.avgMs.toFixed(6).padStart(12)} ms/op`}const u={name:"benchmark",description:"Run performance benchmarks",aliases:["bench","b"],options:[{name:"iterations",short:"n",description:"Number of iterations",type:"number",default:1e4},{name:"suite",short:"s",description:"Benchmark suite to run (all, primitives, objects, arrays)",type:"string",default:"all"},{name:"json",short:"j",description:"Output as JSON",type:"boolean",default:!1},{name:"no-color",description:"Disable colored output",type:"boolean",default:!1}],action:async(e,o)=>{const s=o.iterations,r=o.suite,t=o.json,n=!o["no-color"],c=[],l=i.string(),u=i.number(),f=i.boolean(),g=i.date(),h=i.object({name:i.string(),email:i.string(),age:i.number(),active:i.boolean()}),b=i.array(i.number()),S=i.object({user:i.object({name:i.string(),email:i.string()}),items:i.array(i.object({id:i.number(),name:i.string(),price:i.number()}))}),y="hello world",v=new Date,j={name:"John",email:"john@example.com",age:30,active:!0},w=[1,2,3,4,5,6,7,8,9,10],O={user:{name:"John",email:"john@example.com"},items:[{id:1,name:"Item 1",price:10.99},{id:2,name:"Item 2",price:20.99},{id:3,name:"Item 3",price:30.99}]};if(t||(console.log(a.bold("VLD Performance Benchmark")),console.log(a.dim(`Running ${p(s)} iterations per test`)),console.log("")),("all"===r||"primitives"===r)&&(t||console.log(a.bold("Primitives:")),c.push(m("string.parse()",()=>l.parse(y),s)),c.push(m("number.parse()",()=>u.parse(42),s)),c.push(m("boolean.parse()",()=>f.parse(true),s)),c.push(m("date.parse()",()=>g.parse(v),s)),c.push(m("string.safeParse()",()=>l.safeParse(y),s)),!t)){for(const e of c.slice(-5))console.log(" "+d(e,n));console.log("")}if(("all"===r||"objects"===r)&&(t||console.log(a.bold("Objects:")),c.push(m("object.parse()",()=>h.parse(j),s)),c.push(m("object.safeParse()",()=>h.safeParse(j),s)),c.push(m("nested.parse()",()=>S.parse(O),s)),!t)){for(const e of c.slice(-3))console.log(" "+d(e,n));console.log("")}if(("all"===r||"arrays"===r)&&(t||console.log(a.bold("Arrays:")),c.push(m("array.parse()",()=>b.parse(w),s)),c.push(m("array.safeParse()",()=>b.safeParse(w),s)),!t)){for(const e of c.slice(-2))console.log(" "+d(e,n));console.log("")}if(t)console.log(JSON.stringify({iterations:s,suite:r,results:c.map(e=>({name:e.name,iterations:e.iterations,totalMs:e.totalMs,avgMs:e.avgMs,opsPerSec:e.opsPerSec}))}));else{const e=c.reduce((e,o)=>e+o.opsPerSec,0)/c.length;console.log(a.bold("Summary:")),console.log(` Total benchmarks: ${c.length}`),console.log(` Average ops/sec: ${p(e)}`)}}},f=JSON.parse(s(new URL("../../package.json",import.meta.url),"utf-8")).version||"0.0.0";e.version=f,e.command(l),e.command(u),e.command({name:"help",description:"Show help information",aliases:["h"],action:()=>{console.log(e.help())}}),e.command({name:"version",description:"Show version information",action:()=>{console.log(`vld v${f}`)}}),e.run(process.argv.slice(2)).catch(e=>{console.error("Fatal error:",e),process.exitCode=1});
|