@ramiyohay/schema-faker 0.3.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 ADDED
@@ -0,0 +1,81 @@
1
+ # schema-faker
2
+
3
+ Generate fake data from **Zod schemas** in a deterministic, type-safe, and extensible way.
4
+
5
+ `schema-faker` creates realistic-looking mock data **directly from your existing schemas**, without writing manual mocks.
6
+
7
+ ---
8
+
9
+ ## Why schema-faker?
10
+
11
+ Most fake data libraries generate random values field-by-field.
12
+ `schema-faker` works **schema-first**.
13
+
14
+ ### Benefits
15
+ - ✅ Uses schemas you already have (Zod)
16
+ - ✅ Deterministic output (seed support)
17
+ - ✅ Fully type-safe
18
+ - ✅ No dependency on Faker
19
+ - ✅ Perfect for tests, seeds, and mock APIs
20
+
21
+ ### Type Support
22
+ - ✅ string
23
+ - ✅ number
24
+ - ✅ boolean
25
+ - ✅ object
26
+ - ✅ array
27
+ - ✅ optional
28
+ - ✅ enum
29
+ - ✅ nullable
30
+ - ✅ tuple
31
+ - ✅ union
32
+ - ✅ literal
33
+ - ✅ date
34
+
35
+
36
+ ## Install
37
+ npm install schema-faker zod
38
+
39
+ ## Basic Usage
40
+ ```ts
41
+ import { z } from "zod";
42
+ import { generate } from "schema-faker";
43
+
44
+ const User = z.object({
45
+ id: z.string().uuid(),
46
+ email: z.string().email(),
47
+ age: z.number().min(18)
48
+ });
49
+
50
+ const user = generate(User);
51
+
52
+ // you can also create multi objects
53
+
54
+ const users = generate(User, {
55
+ count: 5,
56
+ seed: 42,
57
+ });
58
+ ```
59
+
60
+ # Override Data Usage
61
+ ```ts
62
+ import { z } from "zod";
63
+ import { generate } from "schema-faker";
64
+
65
+ const UserSchema = z.object({
66
+ id: z.string().uuid(),
67
+ email: z.string().email(),
68
+ age: z.number().min(18).max(65),
69
+ isActive: z.boolean(),
70
+ });
71
+
72
+ // email and age will stay the same
73
+ const user = generate(UserSchema, {
74
+ overrides: {
75
+ email: "test@example.com",
76
+ age: 30,
77
+ },
78
+ });
79
+
80
+ console.log(user);
81
+ ```
@@ -0,0 +1,4 @@
1
+ import { Random } from "./random";
2
+ export type Context = {
3
+ random: Random;
4
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1 @@
1
+ export declare function deepMerge(target: any, source: any): any;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deepMerge = deepMerge;
4
+ // Deeply merges two objects
5
+ function deepMerge(target, source) {
6
+ if (source === null || typeof source !== "object" || Array.isArray(source)) {
7
+ return source;
8
+ }
9
+ if (target === null || typeof target !== "object" || Array.isArray(target)) {
10
+ return source;
11
+ }
12
+ const result = { ...target };
13
+ for (const key of Object.keys(source)) {
14
+ result[key] = deepMerge(target[key], source[key]);
15
+ }
16
+ return result;
17
+ }
@@ -0,0 +1,8 @@
1
+ export declare class Random {
2
+ private seed;
3
+ constructor(seed?: number);
4
+ private next;
5
+ int(min: number, max: number): number;
6
+ bool(): boolean;
7
+ string(length: number): string;
8
+ }
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Random = void 0;
4
+ class Random {
5
+ constructor(seed = Date.now()) {
6
+ this.seed = seed;
7
+ }
8
+ next() {
9
+ this.seed = (this.seed * 9301 + 49297) % 233280;
10
+ return this.seed / 233280;
11
+ }
12
+ int(min, max) {
13
+ return Math.floor(this.next() * (max - min + 1)) + min;
14
+ }
15
+ bool() {
16
+ return this.next() > 0.5;
17
+ }
18
+ string(length) {
19
+ const chars = "abcdefghijklmnopqrstuvwxyz";
20
+ return Array.from({ length }, () => chars[this.int(0, chars.length - 1)]).join("");
21
+ }
22
+ }
23
+ exports.Random = Random;
@@ -0,0 +1,2 @@
1
+ import { GenerateOptions } from "./types";
2
+ export declare function generate(schema: any, options?: GenerateOptions): any;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generate = generate;
4
+ const random_1 = require("./core/random");
5
+ const parseZod_1 = require("./zod/parseZod");
6
+ const deepMerge_1 = require("./core/deepMerge");
7
+ function generate(schema, options = {}) {
8
+ const ctx = {
9
+ random: new random_1.Random(options.seed),
10
+ };
11
+ // create data based on schema
12
+ const generated = (0, parseZod_1.parseZodSchema)(schema, ctx);
13
+ // apply overrides if provided
14
+ if (options.overrides) {
15
+ return (0, deepMerge_1.deepMerge)(generated, options.overrides);
16
+ }
17
+ return generated;
18
+ }
@@ -0,0 +1,2 @@
1
+ import { Context } from "../core/context";
2
+ export declare function generateArray(schema: any, ctx: Context): any[];
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateArray = generateArray;
4
+ const parseZod_1 = require("../zod/parseZod");
5
+ function generateArray(schema, ctx) {
6
+ const min = schema._def.minLength?.value ?? 1;
7
+ const max = schema._def.maxLength?.value ?? min + 4;
8
+ const length = ctx.random.int(min, max);
9
+ const itemSchema = schema._def.type;
10
+ const result = [];
11
+ for (let i = 0; i < length; i++) {
12
+ result.push((0, parseZod_1.parseZodSchema)(itemSchema, ctx));
13
+ }
14
+ return result;
15
+ }
@@ -0,0 +1,2 @@
1
+ import { Context } from "../core/context";
2
+ export declare function generateBoolean(ctx: Context): boolean;
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateBoolean = generateBoolean;
4
+ function generateBoolean(ctx) {
5
+ return ctx.random.bool();
6
+ }
@@ -0,0 +1,2 @@
1
+ import { Context } from "../core/context";
2
+ export declare function generateDate(schema: any, ctx: Context): Date;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateDate = generateDate;
4
+ const DEFAULT_MIN_DATE = new Date("1970-01-01").getTime();
5
+ // Helper to convert Date or number to timestamp
6
+ function toTimestamp(value) {
7
+ if (value instanceof Date) {
8
+ return value.getTime();
9
+ }
10
+ if (typeof value === "number") {
11
+ return value;
12
+ }
13
+ throw new Error("Invalid date constraint value");
14
+ }
15
+ function generateDate(schema, ctx) {
16
+ const checks = schema._def.checks ?? [];
17
+ let min = DEFAULT_MIN_DATE;
18
+ let max = Date.now();
19
+ for (const check of checks) {
20
+ if (check.kind === "min") {
21
+ min = toTimestamp(check.value);
22
+ }
23
+ if (check.kind === "max") {
24
+ max = toTimestamp(check.value);
25
+ }
26
+ }
27
+ // date range validation
28
+ if (min > max) {
29
+ throw new Error("Invalid date range: min > max");
30
+ }
31
+ const timestamp = ctx.random.int(min, max);
32
+ return new Date(timestamp);
33
+ }
@@ -0,0 +1,2 @@
1
+ import { Context } from "../core/context";
2
+ export declare function generateEnum(schema: any, ctx: Context): any;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateEnum = generateEnum;
4
+ function generateEnum(schema, ctx) {
5
+ const values = schema._def.values;
6
+ const index = ctx.random.int(0, values.length - 1);
7
+ return values[index];
8
+ }
@@ -0,0 +1,2 @@
1
+ import { Context } from "../core/context";
2
+ export declare function generateNumber(schema: any, ctx: Context): number;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateNumber = generateNumber;
4
+ function generateNumber(schema, ctx) {
5
+ const checks = schema._def.checks ?? [];
6
+ let min = 0;
7
+ let max = 100;
8
+ for (const check of checks) {
9
+ if (check.kind === "min")
10
+ min = check.value;
11
+ if (check.kind === "max")
12
+ max = check.value;
13
+ }
14
+ return ctx.random.int(min, max);
15
+ }
@@ -0,0 +1,2 @@
1
+ import { Context } from "../core/context";
2
+ export declare function generateString(schema: any, ctx: Context): string;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateString = generateString;
4
+ function generateUUID(ctx) {
5
+ const hex = () => ctx.random.int(0, 15).toString(16);
6
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
7
+ const r = ctx.random.int(0, 15);
8
+ const v = c === "x" ? r : (r & 0x3) | 0x8;
9
+ return v.toString(16);
10
+ });
11
+ }
12
+ function generateString(schema, ctx) {
13
+ const checks = schema._def.checks ?? [];
14
+ if (checks.some((c) => c.kind === "uuid")) {
15
+ return generateUUID(ctx);
16
+ }
17
+ if (checks.some((c) => c.kind === "email")) {
18
+ return `user${ctx.random.int(1, 9999)}@example.com`;
19
+ }
20
+ return ctx.random.string(10);
21
+ }
@@ -0,0 +1 @@
1
+ export { generate } from "./generate";
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generate = void 0;
4
+ var generate_1 = require("./generate");
5
+ Object.defineProperty(exports, "generate", { enumerable: true, get: function () { return generate_1.generate; } });
@@ -0,0 +1,5 @@
1
+ export type GenerateOptions = {
2
+ seed?: number;
3
+ count?: number;
4
+ overrides?: Record<string, any>;
5
+ };
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ import { Context } from "../core/context";
2
+ export declare function parseZodSchema(schema: any, ctx: Context): any;
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseZodSchema = parseZodSchema;
4
+ const string_1 = require("../generators/string");
5
+ const number_1 = require("../generators/number");
6
+ const boolean_1 = require("../generators/boolean");
7
+ const array_1 = require("../generators/array");
8
+ const enum_1 = require("../generators/enum");
9
+ const date_1 = require("../generators/date");
10
+ function parseZodSchema(schema, ctx) {
11
+ switch (schema._def.typeName) {
12
+ case "ZodString": // String type
13
+ return (0, string_1.generateString)(schema, ctx);
14
+ case "ZodNumber": // Number type
15
+ return (0, number_1.generateNumber)(schema, ctx);
16
+ case "ZodBoolean": // Boolean type
17
+ return (0, boolean_1.generateBoolean)(ctx);
18
+ case "ZodArray": // Array type
19
+ return (0, array_1.generateArray)(schema, ctx);
20
+ case "ZodOptional": {
21
+ // 50% undefined, 50% value
22
+ return ctx.random.bool()
23
+ ? undefined
24
+ : parseZodSchema(schema._def.innerType, ctx);
25
+ }
26
+ case "ZodNullable": {
27
+ // 50% null, 50% value
28
+ return ctx.random.bool()
29
+ ? null // important: return null here
30
+ : parseZodSchema(schema._def.innerType, ctx);
31
+ }
32
+ case "ZodEnum": // Enum type, return one of the enum values
33
+ return (0, enum_1.generateEnum)(schema, ctx);
34
+ case "ZodObject": // Object type
35
+ const shape = schema.shape;
36
+ const obj = {};
37
+ for (const key in shape) {
38
+ obj[key] = parseZodSchema(shape[key], ctx);
39
+ }
40
+ return obj;
41
+ case "ZodLiteral": // Literal type, always return the literal value
42
+ return schema._def.value;
43
+ case "ZodUnion": {
44
+ // Union type, randomly pick one of the options
45
+ const options = schema._def.options;
46
+ const index = ctx.random.int(0, options.length - 1);
47
+ return parseZodSchema(options[index], ctx);
48
+ }
49
+ case "ZodTuple": { // Tuple type , create array with fixed length and types
50
+ const items = schema._def.items;
51
+ return items.map((itemSchema) => parseZodSchema(itemSchema, ctx));
52
+ }
53
+ case "ZodDate": // Date type
54
+ return (0, date_1.generateDate)(schema, ctx);
55
+ default:
56
+ return null;
57
+ }
58
+ }
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@ramiyohay/schema-faker",
3
+ "version": "0.3.0",
4
+ "description": "Generate fake data from Zod schemas in a deterministic way",
5
+ "license": "MIT",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "scripts": {
12
+ "build": "tsc",
13
+ "test": "vitest"
14
+ },
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "https://github.com/ramiyohay/schema-faker"
18
+ },
19
+ "keywords": [
20
+ "faker",
21
+ "schema",
22
+ "zod",
23
+ "mock",
24
+ "testing",
25
+ "seed",
26
+ "fake-data"
27
+ ],
28
+ "dependencies": {
29
+ "zod": "^3.23.0"
30
+ },
31
+ "devDependencies": {
32
+ "typescript": "^5.9.3",
33
+ "vitest": "^4.0.16"
34
+ }
35
+ }