@eventvisor/sdk 0.0.2
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/LICENSE +21 -0
- package/README.md +9 -0
- package/dist/attributesManager.d.ts +36 -0
- package/dist/bucketer.d.ts +30 -0
- package/dist/compareVersions.d.ts +4 -0
- package/dist/conditions.d.ts +20 -0
- package/dist/datafileReader.d.ts +29 -0
- package/dist/effectsManager.d.ts +33 -0
- package/dist/emitter.d.ts +11 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +2 -0
- package/dist/index.mjs.gz +0 -0
- package/dist/index.mjs.map +1 -0
- package/dist/instance.d.ts +67 -0
- package/dist/logger.d.ts +26 -0
- package/dist/modulesManager.d.ts +67 -0
- package/dist/murmurhash.d.ts +1 -0
- package/dist/persister.d.ts +40 -0
- package/dist/sourceResolver.d.ts +31 -0
- package/dist/transformer.d.ts +21 -0
- package/dist/validator.d.ts +28 -0
- package/jest.config.js +6 -0
- package/lib/attributesManager.d.ts +36 -0
- package/lib/bucketer.d.ts +30 -0
- package/lib/compareVersions.d.ts +4 -0
- package/lib/conditions.d.ts +20 -0
- package/lib/datafileReader.d.ts +29 -0
- package/lib/effectsManager.d.ts +33 -0
- package/lib/emitter.d.ts +11 -0
- package/lib/index.d.ts +12 -0
- package/lib/instance.d.ts +67 -0
- package/lib/logger.d.ts +26 -0
- package/lib/modulesManager.d.ts +67 -0
- package/lib/murmurhash.d.ts +1 -0
- package/lib/persister.d.ts +40 -0
- package/lib/sourceResolver.d.ts +31 -0
- package/lib/transformer.d.ts +21 -0
- package/lib/validator.d.ts +28 -0
- package/package.json +45 -0
- package/src/attributesManager.ts +181 -0
- package/src/bucketer.spec.ts +156 -0
- package/src/bucketer.ts +152 -0
- package/src/compareVersions.ts +93 -0
- package/src/conditions.ts +224 -0
- package/src/datafileReader.ts +133 -0
- package/src/effectsManager.ts +214 -0
- package/src/emitter.ts +64 -0
- package/src/index.spec.ts +5 -0
- package/src/index.ts +14 -0
- package/src/instance.spec.ts +184 -0
- package/src/instance.ts +608 -0
- package/src/logger.ts +90 -0
- package/src/modulesManager.ts +276 -0
- package/src/murmurhash.ts +71 -0
- package/src/persister.ts +162 -0
- package/src/sourceResolver.spec.ts +253 -0
- package/src/sourceResolver.ts +213 -0
- package/src/transformer.ts +316 -0
- package/src/transformer_static.spec.ts +377 -0
- package/src/transformer_types.spec.ts +820 -0
- package/src/validator.spec.ts +579 -0
- package/src/validator.ts +366 -0
- package/tsconfig.cjs.json +8 -0
- package/tsconfig.esm.json +8 -0
- package/webpack.config.js +80 -0
package/src/validator.ts
ADDED
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
import { JSONSchema, Value } from "@eventvisor/types";
|
|
2
|
+
|
|
3
|
+
import type { GetSourceResolver } from "./sourceResolver";
|
|
4
|
+
import type { Logger } from "./logger";
|
|
5
|
+
|
|
6
|
+
export interface ValidatorOptions {
|
|
7
|
+
logger: Logger;
|
|
8
|
+
getSourceResolver: GetSourceResolver;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export class Validator {
|
|
12
|
+
private logger: Logger;
|
|
13
|
+
private getSourceResolver: GetSourceResolver;
|
|
14
|
+
|
|
15
|
+
constructor(options: ValidatorOptions) {
|
|
16
|
+
this.logger = options.logger;
|
|
17
|
+
this.getSourceResolver = options.getSourceResolver;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
validate(schema: JSONSchema, value: Value): Promise<ValidationResult> {
|
|
21
|
+
const deps: ValidationDependencies = {};
|
|
22
|
+
|
|
23
|
+
return validate(schema, value, deps);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface ValidationError {
|
|
28
|
+
path: string;
|
|
29
|
+
message: string;
|
|
30
|
+
schema?: JSONSchema;
|
|
31
|
+
value?: Value;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface ValidationResult {
|
|
35
|
+
valid: boolean;
|
|
36
|
+
errors?: ValidationError[];
|
|
37
|
+
value?: Value;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface ValidationDependencies {
|
|
41
|
+
[key: string]: any;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export async function validate(
|
|
45
|
+
schema: JSONSchema,
|
|
46
|
+
value: Value,
|
|
47
|
+
deps: ValidationDependencies,
|
|
48
|
+
): Promise<ValidationResult> {
|
|
49
|
+
const errors: ValidationError[] = [];
|
|
50
|
+
const result = validateValue(schema, value, "", errors, deps);
|
|
51
|
+
|
|
52
|
+
// Only apply default if there are no validation errors and result is undefined
|
|
53
|
+
if (result === undefined && errors.length === 0 && schema.default !== undefined) {
|
|
54
|
+
return {
|
|
55
|
+
valid: true,
|
|
56
|
+
value: schema.default,
|
|
57
|
+
errors: [],
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
valid: errors.length === 0,
|
|
63
|
+
errors: errors.length > 0 ? errors : undefined,
|
|
64
|
+
value: result,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function validateValue(
|
|
69
|
+
schema: JSONSchema,
|
|
70
|
+
value: Value,
|
|
71
|
+
path: string,
|
|
72
|
+
errors: ValidationError[],
|
|
73
|
+
deps: ValidationDependencies,
|
|
74
|
+
): Value | undefined {
|
|
75
|
+
// Handle null values
|
|
76
|
+
if (value === null) {
|
|
77
|
+
if ((schema.type as any) === "null" || schema.enum?.includes(null)) {
|
|
78
|
+
return value;
|
|
79
|
+
}
|
|
80
|
+
if (schema.type && (schema.type as any) !== "null") {
|
|
81
|
+
errors.push({
|
|
82
|
+
path,
|
|
83
|
+
message: `Expected type ${schema.type}, got null`,
|
|
84
|
+
schema,
|
|
85
|
+
value,
|
|
86
|
+
});
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Handle undefined values
|
|
92
|
+
if (value === undefined) {
|
|
93
|
+
if (schema.default !== undefined) {
|
|
94
|
+
return schema.default;
|
|
95
|
+
}
|
|
96
|
+
if (schema.type) {
|
|
97
|
+
errors.push({
|
|
98
|
+
path,
|
|
99
|
+
message: `Required field missing`,
|
|
100
|
+
schema,
|
|
101
|
+
value,
|
|
102
|
+
});
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Type validation (but allow number for integer type to handle specific validation)
|
|
109
|
+
if (schema.type && schema.type !== "integer") {
|
|
110
|
+
const typeValid = validateType(schema.type, value);
|
|
111
|
+
if (!typeValid) {
|
|
112
|
+
errors.push({
|
|
113
|
+
path,
|
|
114
|
+
message: `Expected type ${schema.type}, got ${typeof value}`,
|
|
115
|
+
schema,
|
|
116
|
+
value,
|
|
117
|
+
});
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Const validation
|
|
123
|
+
if (schema.const !== undefined && value !== schema.const) {
|
|
124
|
+
errors.push({
|
|
125
|
+
path,
|
|
126
|
+
message: `Value must be exactly ${JSON.stringify(schema.const)}`,
|
|
127
|
+
schema,
|
|
128
|
+
value,
|
|
129
|
+
});
|
|
130
|
+
return undefined;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Enum validation
|
|
134
|
+
if (schema.enum && !schema.enum.includes(value)) {
|
|
135
|
+
errors.push({
|
|
136
|
+
path,
|
|
137
|
+
message: `Value must be one of: ${schema.enum.map((v) => JSON.stringify(v)).join(", ")}`,
|
|
138
|
+
schema,
|
|
139
|
+
value,
|
|
140
|
+
});
|
|
141
|
+
return undefined;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
let result = value;
|
|
145
|
+
|
|
146
|
+
// Object validation
|
|
147
|
+
if (typeof value === "object" && !Array.isArray(value) && schema.properties) {
|
|
148
|
+
// Handle JavaScript Error objects specially
|
|
149
|
+
let obj: Record<string, Value>;
|
|
150
|
+
if (value instanceof Error) {
|
|
151
|
+
obj = {
|
|
152
|
+
name: value.name,
|
|
153
|
+
message: value.message,
|
|
154
|
+
stack: value.stack,
|
|
155
|
+
...(value as any), // Include any additional properties
|
|
156
|
+
};
|
|
157
|
+
} else {
|
|
158
|
+
obj = value as Record<string, Value>;
|
|
159
|
+
}
|
|
160
|
+
const validatedObj: Record<string, Value> = {};
|
|
161
|
+
|
|
162
|
+
// Validate required properties
|
|
163
|
+
if (schema.required) {
|
|
164
|
+
for (const requiredProp of schema.required) {
|
|
165
|
+
if (!(requiredProp in obj)) {
|
|
166
|
+
if (schema.properties[requiredProp]?.default !== undefined) {
|
|
167
|
+
validatedObj[requiredProp] = schema.properties[requiredProp].default!;
|
|
168
|
+
} else {
|
|
169
|
+
errors.push({
|
|
170
|
+
path: path ? `${path}.${requiredProp}` : requiredProp,
|
|
171
|
+
message: `Required property '${requiredProp}' is missing`,
|
|
172
|
+
schema: schema.properties[requiredProp],
|
|
173
|
+
value: undefined,
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Validate all properties
|
|
181
|
+
for (const [prop, propValue] of Object.entries(obj)) {
|
|
182
|
+
if (schema.properties && schema.properties[prop]) {
|
|
183
|
+
const propSchema = schema.properties[prop];
|
|
184
|
+
const propPath = path ? `${path}.${prop}` : prop;
|
|
185
|
+
const validatedProp = validateValue(propSchema, propValue, propPath, errors, deps);
|
|
186
|
+
if (validatedProp !== undefined) {
|
|
187
|
+
validatedObj[prop] = validatedProp;
|
|
188
|
+
}
|
|
189
|
+
} else {
|
|
190
|
+
// Allow additional properties by default (JSON Schema behavior)
|
|
191
|
+
validatedObj[prop] = propValue;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Apply defaults for missing optional properties
|
|
196
|
+
if (schema.properties) {
|
|
197
|
+
for (const [prop, propSchema] of Object.entries(schema.properties)) {
|
|
198
|
+
if (!(prop in validatedObj) && propSchema.default !== undefined) {
|
|
199
|
+
validatedObj[prop] = propSchema.default;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
result = validatedObj;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Array validation
|
|
208
|
+
if (Array.isArray(value)) {
|
|
209
|
+
// Array length validation - check before processing items
|
|
210
|
+
if (schema.minItems !== undefined && value.length < schema.minItems) {
|
|
211
|
+
errors.push({
|
|
212
|
+
path,
|
|
213
|
+
message: `Array must have at least ${schema.minItems} items, got ${value.length}`,
|
|
214
|
+
schema,
|
|
215
|
+
value,
|
|
216
|
+
});
|
|
217
|
+
return undefined;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (schema.maxItems !== undefined && value.length > schema.maxItems) {
|
|
221
|
+
errors.push({
|
|
222
|
+
path,
|
|
223
|
+
message: `Array must have at most ${schema.maxItems} items, got ${value.length}`,
|
|
224
|
+
schema,
|
|
225
|
+
value,
|
|
226
|
+
});
|
|
227
|
+
return undefined;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (schema.items) {
|
|
231
|
+
const validatedArray: Value[] = [];
|
|
232
|
+
|
|
233
|
+
if (Array.isArray(schema.items)) {
|
|
234
|
+
// Tuple validation
|
|
235
|
+
for (let i = 0; i < value.length; i++) {
|
|
236
|
+
const itemSchema = schema.items[i];
|
|
237
|
+
if (itemSchema) {
|
|
238
|
+
const itemPath = `${path}[${i}]`;
|
|
239
|
+
const validatedItem = validateValue(itemSchema, value[i], itemPath, errors, deps);
|
|
240
|
+
if (validatedItem !== undefined) {
|
|
241
|
+
validatedArray.push(validatedItem);
|
|
242
|
+
}
|
|
243
|
+
} else {
|
|
244
|
+
validatedArray.push(value[i]);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
} else {
|
|
248
|
+
// Single schema for all items
|
|
249
|
+
for (let i = 0; i < value.length; i++) {
|
|
250
|
+
const itemPath = `${path}[${i}]`;
|
|
251
|
+
const validatedItem = validateValue(schema.items, value[i], itemPath, errors, deps);
|
|
252
|
+
if (validatedItem !== undefined) {
|
|
253
|
+
validatedArray.push(validatedItem);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
result = validatedArray;
|
|
259
|
+
} else {
|
|
260
|
+
result = value;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// String validation
|
|
265
|
+
if (typeof value === "string") {
|
|
266
|
+
if (schema.minLength !== undefined && value.length < schema.minLength) {
|
|
267
|
+
errors.push({
|
|
268
|
+
path,
|
|
269
|
+
message: `String must be at least ${schema.minLength} characters long`,
|
|
270
|
+
schema,
|
|
271
|
+
value,
|
|
272
|
+
});
|
|
273
|
+
return undefined;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (schema.maxLength !== undefined && value.length > schema.maxLength) {
|
|
277
|
+
errors.push({
|
|
278
|
+
path,
|
|
279
|
+
message: `String must be at most ${schema.maxLength} characters long`,
|
|
280
|
+
schema,
|
|
281
|
+
value,
|
|
282
|
+
});
|
|
283
|
+
return undefined;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (schema.pattern) {
|
|
287
|
+
const regex = new RegExp(schema.pattern);
|
|
288
|
+
if (!regex.test(value)) {
|
|
289
|
+
errors.push({
|
|
290
|
+
path,
|
|
291
|
+
message: `String must match pattern: ${schema.pattern}`,
|
|
292
|
+
schema,
|
|
293
|
+
value,
|
|
294
|
+
});
|
|
295
|
+
return undefined;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Number validation
|
|
301
|
+
if (typeof value === "number") {
|
|
302
|
+
if (schema.minimum !== undefined && value < schema.minimum) {
|
|
303
|
+
errors.push({
|
|
304
|
+
path,
|
|
305
|
+
message: `Number must be at least ${schema.minimum}`,
|
|
306
|
+
schema,
|
|
307
|
+
value,
|
|
308
|
+
});
|
|
309
|
+
return undefined;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (schema.maximum !== undefined && value > schema.maximum) {
|
|
313
|
+
errors.push({
|
|
314
|
+
path,
|
|
315
|
+
message: `Number must be at most ${schema.maximum}`,
|
|
316
|
+
schema,
|
|
317
|
+
value,
|
|
318
|
+
});
|
|
319
|
+
return undefined;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
if (schema.type === "integer" && !Number.isInteger(value)) {
|
|
323
|
+
errors.push({
|
|
324
|
+
path,
|
|
325
|
+
message: "Number must be an integer",
|
|
326
|
+
schema,
|
|
327
|
+
value,
|
|
328
|
+
});
|
|
329
|
+
return undefined;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Integer type validation (after number validation)
|
|
334
|
+
if (schema.type === "integer" && typeof value !== "number") {
|
|
335
|
+
errors.push({
|
|
336
|
+
path,
|
|
337
|
+
message: `Expected type integer, got ${typeof value}`,
|
|
338
|
+
schema,
|
|
339
|
+
value,
|
|
340
|
+
});
|
|
341
|
+
return undefined;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
return result;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function validateType(expectedType: string, value: Value): boolean {
|
|
348
|
+
switch (expectedType) {
|
|
349
|
+
case "string":
|
|
350
|
+
return typeof value === "string";
|
|
351
|
+
case "number":
|
|
352
|
+
return typeof value === "number";
|
|
353
|
+
case "integer":
|
|
354
|
+
return typeof value === "number" && Number.isInteger(value);
|
|
355
|
+
case "boolean":
|
|
356
|
+
return typeof value === "boolean";
|
|
357
|
+
case "null":
|
|
358
|
+
return value === null;
|
|
359
|
+
case "object":
|
|
360
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
361
|
+
case "array":
|
|
362
|
+
return Array.isArray(value);
|
|
363
|
+
default:
|
|
364
|
+
return true; // Unknown type, assume valid
|
|
365
|
+
}
|
|
366
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
const path = require("path");
|
|
2
|
+
|
|
3
|
+
module.exports = [
|
|
4
|
+
// cjs
|
|
5
|
+
{
|
|
6
|
+
entry: {
|
|
7
|
+
"index.cjs": path.join(__dirname, "src", "index.ts"),
|
|
8
|
+
},
|
|
9
|
+
output: {
|
|
10
|
+
path: path.join(__dirname, "dist"),
|
|
11
|
+
filename: "index.js",
|
|
12
|
+
library: "EventvisorSDK",
|
|
13
|
+
libraryTarget: "umd",
|
|
14
|
+
globalObject: "this",
|
|
15
|
+
},
|
|
16
|
+
mode: "production",
|
|
17
|
+
devtool: "source-map",
|
|
18
|
+
resolve: {
|
|
19
|
+
extensions: [".ts", ".tsx", ".js"],
|
|
20
|
+
},
|
|
21
|
+
module: {
|
|
22
|
+
rules: [
|
|
23
|
+
{
|
|
24
|
+
test: /\.(ts|tsx)$/,
|
|
25
|
+
exclude: /(node_modules)/,
|
|
26
|
+
use: [
|
|
27
|
+
{
|
|
28
|
+
loader: "ts-loader",
|
|
29
|
+
options: {
|
|
30
|
+
configFile: path.join(__dirname, "tsconfig.cjs.json"),
|
|
31
|
+
transpileOnly: true,
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
performance: {
|
|
39
|
+
hints: false,
|
|
40
|
+
},
|
|
41
|
+
optimization: {
|
|
42
|
+
minimize: true,
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
// esm
|
|
47
|
+
{
|
|
48
|
+
entry: path.join(__dirname, "src", "index.ts"),
|
|
49
|
+
output: {
|
|
50
|
+
path: path.join(__dirname, "dist"),
|
|
51
|
+
filename: "index.mjs",
|
|
52
|
+
library: {
|
|
53
|
+
type: "module",
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
experiments: {
|
|
57
|
+
outputModule: true,
|
|
58
|
+
},
|
|
59
|
+
mode: "production",
|
|
60
|
+
devtool: "source-map",
|
|
61
|
+
resolve: {
|
|
62
|
+
extensions: [".ts", ".tsx", ".js"],
|
|
63
|
+
},
|
|
64
|
+
module: {
|
|
65
|
+
rules: [
|
|
66
|
+
{
|
|
67
|
+
test: /\.(ts|tsx)$/,
|
|
68
|
+
exclude: /(node_modules)/,
|
|
69
|
+
loader: "ts-loader",
|
|
70
|
+
options: {
|
|
71
|
+
configFile: path.join(__dirname, "tsconfig.esm.json"),
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
},
|
|
76
|
+
performance: {
|
|
77
|
+
hints: false,
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
];
|