@schmock/faker 2.2.3 → 2.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.
Files changed (65) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +45 -0
  3. package/dist/constants.d.ts +82 -1
  4. package/dist/constants.d.ts.map +1 -1
  5. package/dist/field-mappings.d.ts.map +1 -1
  6. package/dist/field-name-matcher.d.ts +19 -0
  7. package/dist/field-name-matcher.d.ts.map +1 -1
  8. package/dist/index.d.ts +3 -0
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +4 -1
  11. package/dist/jsf-config.d.ts +27 -2
  12. package/dist/jsf-config.d.ts.map +1 -1
  13. package/dist/output-limits.d.ts +3 -0
  14. package/dist/output-limits.d.ts.map +1 -0
  15. package/dist/overrides.d.ts +2 -1
  16. package/dist/overrides.d.ts.map +1 -1
  17. package/dist/schema-children.d.ts +14 -0
  18. package/dist/schema-children.d.ts.map +1 -0
  19. package/dist/schema-enhancement.d.ts +1 -0
  20. package/dist/schema-enhancement.d.ts.map +1 -1
  21. package/dist/validation.d.ts +24 -5
  22. package/dist/validation.d.ts.map +1 -1
  23. package/package.json +19 -9
  24. package/dist/constants.js +0 -8
  25. package/dist/field-mappings.js +0 -1107
  26. package/dist/field-name-matcher.js +0 -149
  27. package/dist/jsf-config.js +0 -35
  28. package/dist/overrides.js +0 -131
  29. package/dist/schema-enhancement.js +0 -89
  30. package/dist/test-utils.d.ts +0 -57
  31. package/dist/test-utils.d.ts.map +0 -1
  32. package/dist/test-utils.js +0 -271
  33. package/dist/validation.js +0 -300
  34. package/src/advanced-features.test.ts +0 -912
  35. package/src/audit-faker-args.test.ts +0 -97
  36. package/src/constants.d.ts.map +0 -1
  37. package/src/constants.ts +0 -9
  38. package/src/data-quality.test.ts +0 -415
  39. package/src/error-handling.test.ts +0 -504
  40. package/src/field-mappings.test.ts +0 -351
  41. package/src/field-mappings.ts +0 -1141
  42. package/src/field-name-matcher.test.ts +0 -292
  43. package/src/field-name-matcher.ts +0 -188
  44. package/src/index.d.ts.map +0 -1
  45. package/src/index.test.ts +0 -1218
  46. package/src/index.ts +0 -168
  47. package/src/integration.test.ts +0 -634
  48. package/src/jsf-config.d.ts.map +0 -1
  49. package/src/jsf-config.ts +0 -48
  50. package/src/overrides.d.ts.map +0 -1
  51. package/src/overrides.property.test.ts +0 -172
  52. package/src/overrides.test.ts +0 -38
  53. package/src/overrides.ts +0 -176
  54. package/src/performance.test.ts +0 -494
  55. package/src/plugin-integration.test.ts +0 -575
  56. package/src/post-process.test.ts +0 -151
  57. package/src/real-world.test.ts +0 -636
  58. package/src/schema-enhancement.d.ts.map +0 -1
  59. package/src/schema-enhancement.test.ts +0 -216
  60. package/src/schema-enhancement.ts +0 -128
  61. package/src/steps/deterministic-seeds.steps.ts +0 -35
  62. package/src/steps/faker-plugin.steps.ts +0 -109
  63. package/src/test-utils.ts +0 -365
  64. package/src/validation.d.ts.map +0 -1
  65. package/src/validation.ts +0 -417
@@ -1,494 +0,0 @@
1
- import type { JSONSchema7 } from "json-schema";
2
- import { describe, expect, it } from "vitest";
3
- import { fakerPlugin, generateFromSchema } from "./index";
4
- import { generate, performance as perf, schemas } from "./test-utils";
5
-
6
- describe("Performance and Memory", () => {
7
- describe("Generation Speed", () => {
8
- it("generates simple objects quickly", async () => {
9
- const schema = schemas.simple.object({
10
- id: schemas.simple.number(),
11
- name: schemas.simple.string(),
12
- active: { type: "boolean" },
13
- });
14
-
15
- const times: number[] = [];
16
- for (let i = 0; i < 10; i++) {
17
- const { duration } = await perf.measure(
18
- async () => await generateFromSchema({ schema }),
19
- );
20
- times.push(duration);
21
- }
22
-
23
- const avgTime = times.reduce((a, b) => a + b, 0) / times.length;
24
- expect(avgTime).toBeLessThan(50); // Should average under 50ms
25
- });
26
-
27
- it("handles nested objects efficiently", async () => {
28
- const schema = schemas.nested.deep(
29
- 3,
30
- schemas.simple.object({
31
- id: schemas.simple.number(),
32
- value: schemas.simple.string(),
33
- }),
34
- );
35
-
36
- const { duration } = await perf.measure(
37
- async () => await generateFromSchema({ schema }),
38
- );
39
-
40
- expect(duration).toBeLessThan(100); // Reasonable for nested structure
41
- });
42
-
43
- it("generates arrays efficiently", async () => {
44
- const schema = schemas.simple.array(
45
- schemas.simple.object({
46
- id: schemas.simple.number(),
47
- name: schemas.simple.string(),
48
- }),
49
- { minItems: 50, maxItems: 50 },
50
- );
51
-
52
- const { duration } = await perf.measure(
53
- async () => await generateFromSchema({ schema }),
54
- );
55
-
56
- expect(duration).toBeLessThan(200); // Should handle 50 items quickly
57
- });
58
-
59
- it("handles complex schemas with multiple constraints", async () => {
60
- const schema: JSONSchema7 = {
61
- type: "object",
62
- properties: {
63
- users: {
64
- type: "array",
65
- items: {
66
- type: "object",
67
- properties: {
68
- id: { type: "string", format: "uuid" },
69
- email: { type: "string", format: "email" },
70
- age: { type: "integer", minimum: 18, maximum: 100 },
71
- tags: {
72
- type: "array",
73
- items: { type: "string", pattern: "^[a-z]+$" },
74
- maxItems: 5,
75
- },
76
- },
77
- required: ["id", "email"],
78
- },
79
- minItems: 10,
80
- maxItems: 10,
81
- },
82
- },
83
- };
84
-
85
- const { duration } = await perf.measure(
86
- async () => await generateFromSchema({ schema }),
87
- );
88
-
89
- expect(duration).toBeLessThan(300); // Complex but still reasonable
90
- });
91
- });
92
-
93
- describe("Scaling Behavior", () => {
94
- it("scales linearly with array size", async () => {
95
- const smallSchema = schemas.simple.array(schemas.simple.string(), {
96
- minItems: 50,
97
- maxItems: 50,
98
- });
99
-
100
- const largeSchema = schemas.simple.array(schemas.simple.string(), {
101
- minItems: 500,
102
- maxItems: 500,
103
- });
104
-
105
- // Warmup runs to stabilize JIT
106
- for (let i = 0; i < 3; i++) {
107
- await generateFromSchema({ schema: smallSchema });
108
- await generateFromSchema({ schema: largeSchema });
109
- }
110
-
111
- // Multiple measurement runs for statistical stability
112
- const smallTimes: number[] = [];
113
- const largeTimes: number[] = [];
114
-
115
- for (let i = 0; i < 10; i++) {
116
- const start1 = performance.now();
117
- await generateFromSchema({ schema: smallSchema });
118
- const small = performance.now() - start1;
119
- smallTimes.push(small);
120
-
121
- const start2 = performance.now();
122
- await generateFromSchema({ schema: largeSchema });
123
- const large = performance.now() - start2;
124
- largeTimes.push(large);
125
- }
126
-
127
- // Remove outliers and calculate medians for stability
128
- smallTimes.sort((a, b) => a - b);
129
- largeTimes.sort((a, b) => a - b);
130
- const medianSmall = smallTimes[Math.floor(smallTimes.length / 2)];
131
- const medianLarge = largeTimes[Math.floor(largeTimes.length / 2)];
132
-
133
- // Both should complete in reasonable time (main goal is to ensure it works, not strict timing)
134
- expect(medianSmall).toBeLessThan(50); // Small arrays should be fast
135
- expect(medianLarge).toBeLessThan(200); // Large arrays should still be reasonable
136
-
137
- // Optional: Check scaling if timing is meaningful
138
- if (medianSmall > 0.1) {
139
- // Only check scaling if we have measurable timing
140
- expect(medianLarge).toBeGreaterThan(medianSmall * 0.5); // Should take at least half as long
141
- expect(medianLarge).toBeLessThan(medianSmall * 50); // But not extremely longer
142
- }
143
- });
144
-
145
- it("handles wide objects efficiently", async () => {
146
- const narrowSchema = schemas.nested.wide(20);
147
- const wideSchema = schemas.nested.wide(100);
148
-
149
- // Warmup
150
- for (let i = 0; i < 3; i++) {
151
- await generateFromSchema({ schema: narrowSchema });
152
- await generateFromSchema({ schema: wideSchema });
153
- }
154
-
155
- // Measure with multiple runs, dropping outliers
156
- const narrowTimes: number[] = [];
157
- const wideTimes: number[] = [];
158
-
159
- for (let i = 0; i < 10; i++) {
160
- const start1 = performance.now();
161
- await generateFromSchema({ schema: narrowSchema });
162
- narrowTimes.push(performance.now() - start1);
163
-
164
- const start2 = performance.now();
165
- await generateFromSchema({ schema: wideSchema });
166
- wideTimes.push(performance.now() - start2);
167
- }
168
-
169
- // Use median instead of average to reduce sensitivity to GC pauses
170
- const median = (arr: number[]) => {
171
- const sorted = [...arr].sort((a, b) => a - b);
172
- const mid = Math.floor(sorted.length / 2);
173
- return sorted.length % 2
174
- ? sorted[mid]
175
- : (sorted[mid - 1] + sorted[mid]) / 2;
176
- };
177
-
178
- const medNarrow = median(narrowTimes);
179
- const medWide = median(wideTimes);
180
-
181
- // Scale assertion (machine-speed-independent): wide has 5x the
182
- // properties of narrow, so its generation time should scale roughly
183
- // with that. Allow 20x headroom for measurement noise + small superlinear
184
- // behavior; this catches order-of-magnitude regressions without flaking
185
- // on shared CI runners where absolute wall-clock thresholds are unreliable.
186
- if (medNarrow > 0.1) {
187
- // Only check scaling if we have measurable timing
188
- expect(medWide).toBeGreaterThan(medNarrow * 0.5); // sanity: more work, not less
189
- expect(medWide).toBeLessThan(medNarrow * 20); // catches >4x-per-property regressions
190
- }
191
- });
192
- });
193
-
194
- describe("Plugin Performance", () => {
195
- it("plugin creation is fast", async () => {
196
- const schema = schemas.complex.user();
197
-
198
- const { duration } = await perf.measure(() => fakerPlugin({ schema }));
199
-
200
- expect(duration).toBeLessThan(10); // Plugin creation should be instant
201
- });
202
-
203
- it("plugin processing adds minimal overhead", async () => {
204
- const schema = schemas.complex.apiResponse();
205
- const plugin = fakerPlugin({ schema });
206
-
207
- const context = {
208
- method: "GET",
209
- path: "/test",
210
- params: {},
211
- query: {},
212
- state: {},
213
- headers: {},
214
- body: null,
215
- route: {},
216
- };
217
-
218
- const times: number[] = [];
219
- for (let i = 0; i < 10; i++) {
220
- const { duration } = await perf.measure(() => plugin.process(context));
221
- times.push(duration);
222
- }
223
-
224
- const avgTime = times.reduce((a, b) => a + b, 0) / times.length;
225
- expect(avgTime).toBeLessThan(100);
226
- });
227
-
228
- it("template processing is efficient", async () => {
229
- const schema = schemas.simple.object({
230
- id: schemas.simple.string(),
231
- userId: schemas.simple.string(),
232
- timestamp: schemas.simple.string(),
233
- message: schemas.simple.string(),
234
- });
235
-
236
- const overrides = {
237
- id: "{{params.id}}",
238
- userId: "{{state.user.id}}",
239
- timestamp: "{{state.timestamp}}",
240
- message: "User {{params.id}} at {{state.timestamp}}",
241
- };
242
-
243
- const { duration } = await perf.measure(
244
- async () =>
245
- await generateFromSchema({
246
- schema,
247
- overrides,
248
- params: { id: "123" },
249
- state: {
250
- user: { id: "user-456" },
251
- timestamp: new Date().toISOString(),
252
- },
253
- }),
254
- );
255
-
256
- expect(duration).toBeLessThan(50); // Template processing should be fast
257
- });
258
- });
259
-
260
- describe("Concurrent Generation", () => {
261
- it("handles multiple concurrent generations", async () => {
262
- const schema = schemas.complex.user();
263
-
264
- const { duration } = await perf.measure(async () => {
265
- const promises = Array.from(
266
- { length: 20 },
267
- async () => await generateFromSchema({ schema }),
268
- );
269
- await Promise.all(promises);
270
- });
271
-
272
- expect(duration).toBeLessThan(500); // Should handle concurrency well
273
- });
274
-
275
- it("maintains performance under load", async () => {
276
- const schema = schemas.simple.object({
277
- id: schemas.simple.number(),
278
- data: schemas.simple.string(),
279
- });
280
-
281
- // Warm up
282
- await generateFromSchema({ schema });
283
-
284
- // Test under load
285
- const iterations = 100;
286
- const { duration } = await perf.measure(async () => {
287
- for (let i = 0; i < iterations; i++) {
288
- await generateFromSchema({ schema });
289
- }
290
- });
291
-
292
- const avgTime = duration / iterations;
293
- expect(avgTime).toBeLessThan(10); // Should maintain speed
294
- });
295
- });
296
-
297
- describe("Memory Efficiency", () => {
298
- it("doesn't leak memory on repeated generation", async () => {
299
- const schema = schemas.simple.object({
300
- id: schemas.simple.number(),
301
- name: schemas.simple.string(),
302
- });
303
-
304
- // Generate many times
305
- for (let i = 0; i < 1000; i++) {
306
- const result = await generateFromSchema({ schema });
307
- // Result should be garbage collectable
308
- expect(result).toBeDefined();
309
- }
310
-
311
- // If we got here without crashing, memory is managed well
312
- expect(true).toBe(true);
313
- });
314
-
315
- it("handles large data structures without excessive memory", async () => {
316
- const schema = schemas.simple.array(
317
- schemas.simple.object({
318
- id: schemas.simple.string(),
319
- data: schemas.simple.string(),
320
- }),
321
- { minItems: 1000, maxItems: 1000 },
322
- );
323
-
324
- // Should be able to generate without memory issues
325
- const result = await generateFromSchema({ schema });
326
- expect(result).toHaveLength(1000);
327
- });
328
-
329
- it("cleans up after schema validation errors", async () => {
330
- // Generate errors repeatedly
331
- for (let i = 0; i < 100; i++) {
332
- try {
333
- await generateFromSchema({ schema: { type: "invalid" as any } });
334
- } catch (_e) {
335
- // Expected
336
- }
337
- }
338
-
339
- // Should not have memory leaks from error objects
340
- expect(true).toBe(true);
341
- });
342
- });
343
-
344
- describe("Optimization Opportunities", () => {
345
- it("generates data consistently across multiple calls", async () => {
346
- const schema = schemas.simple.object({
347
- email: schemas.simple.string(),
348
- firstName: schemas.simple.string(),
349
- phone: schemas.simple.string(),
350
- });
351
-
352
- // Generate multiple times to ensure consistent behavior
353
- const results: any[] = [];
354
- for (let i = 0; i < 10; i++) {
355
- const result = await generateFromSchema({ schema });
356
- results.push(result);
357
- }
358
-
359
- // Verify all results have the expected structure
360
- results.forEach((result) => {
361
- expect(result).toHaveProperty("email");
362
- expect(result).toHaveProperty("firstName");
363
- expect(result).toHaveProperty("phone");
364
- expect(typeof result.email).toBe("string");
365
- expect(typeof result.firstName).toBe("string");
366
- expect(typeof result.phone).toBe("string");
367
- });
368
-
369
- // Verify that smart field mapping worked across all calls
370
- const emails = results.map((r) => r.email);
371
- const firstNames = results.map((r) => r.firstName);
372
-
373
- // Should have good diversity (no exact duplicates expected)
374
- const uniqueEmails = new Set(emails);
375
- const uniqueFirstNames = new Set(firstNames);
376
- expect(uniqueEmails.size).toBeGreaterThan(1);
377
- expect(uniqueFirstNames.size).toBeGreaterThan(1);
378
- });
379
-
380
- it("reuses schema enhancement for repeated generations", async () => {
381
- const schema = schemas.complex.user();
382
- const plugin = fakerPlugin({ schema });
383
-
384
- const context = {
385
- method: "GET",
386
- path: "/test",
387
- params: {},
388
- query: {},
389
- state: {},
390
- headers: {},
391
- body: null,
392
- route: {},
393
- };
394
-
395
- // Warmup
396
- for (let i = 0; i < 3; i++) {
397
- plugin.process(context);
398
- }
399
-
400
- // Multiple calls through same plugin with proper timing
401
- const times: number[] = [];
402
- for (let i = 0; i < 15; i++) {
403
- const start = performance.now();
404
- plugin.process(context);
405
- times.push(performance.now() - start);
406
- }
407
-
408
- // Calculate statistics
409
- const avgTime = times.reduce((a, b) => a + b, 0) / times.length;
410
- const maxTime = Math.max(...times);
411
- const minTime = Math.min(...times);
412
-
413
- // Performance should be consistent and reasonable
414
- expect(avgTime).toBeLessThan(50); // Should be reasonably fast
415
- expect(maxTime).toBeLessThan(100); // No extreme outliers
416
- expect(minTime).toBeGreaterThanOrEqual(0); // Valid timing
417
-
418
- // All measurements should be reasonable - no extreme variance
419
- const reasonableMaxTime = Math.max(avgTime * 5, 10); // At least 10ms tolerance
420
- expect(maxTime).toBeLessThan(reasonableMaxTime);
421
- });
422
- });
423
-
424
- describe("Edge Case Performance", () => {
425
- it("handles empty schemas efficiently", async () => {
426
- const schema = schemas.simple.object({});
427
-
428
- const { duration } = await perf.measure(
429
- async () => await generateFromSchema({ schema }),
430
- );
431
-
432
- expect(duration).toBeLessThan(10); // Empty should be instant
433
- });
434
-
435
- it("handles schemas with many enum values", async () => {
436
- const schema = schemas.simple.object({
437
- country: {
438
- type: "string",
439
- enum: Array.from({ length: 200 }, (_, i) => `country-${i}`),
440
- },
441
- });
442
-
443
- const { duration } = await perf.measure(
444
- async () => await generateFromSchema({ schema }),
445
- );
446
-
447
- expect(duration).toBeLessThan(50); // Large enum shouldn't be slow
448
- });
449
-
450
- it("handles complex regex patterns efficiently", async () => {
451
- const schema = schemas.simple.object({
452
- code: {
453
- type: "string",
454
- pattern: "^[A-Z]{2}-[0-9]{4}-[a-z]{2}-[0-9A-F]{8}$",
455
- },
456
- });
457
-
458
- const { duration } = await perf.measure(() =>
459
- generate.samples(schema, 10),
460
- );
461
-
462
- expect(duration).toBeLessThan(100); // Complex patterns OK
463
- });
464
-
465
- it("handles mixed constraint schemas", async () => {
466
- const schema: JSONSchema7 = {
467
- anyOf: [
468
- {
469
- type: "object",
470
- properties: {
471
- type: { const: "A" },
472
- data: { type: "string", minLength: 100 },
473
- },
474
- },
475
- {
476
- type: "array",
477
- items: { type: "number", minimum: 0, maximum: 1000 },
478
- minItems: 50,
479
- },
480
- {
481
- type: "string",
482
- pattern: "^[A-Za-z0-9+/]{100,}={0,2}$",
483
- },
484
- ],
485
- };
486
-
487
- const { duration } = await perf.measure(
488
- async () => await generateFromSchema({ schema }),
489
- );
490
-
491
- expect(duration).toBeLessThan(200); // Complex but manageable
492
- });
493
- });
494
- });