@wylan24/mockgen 0.0.0-stage → 0.1.0-alpha.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.js","sourceRoot":"","sources":["../src/generate.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Faker } from '@faker-js/faker';\nimport { faker as enFaker } from '@faker-js/faker/locale/en';\nimport RandExp from 'randexp';\nimport type { Schema } from './model.js';\nimport { countMatches, type Discriminator, discriminatorOf, fits, mergeAllOf, mergeBranch, typeOf } from './schema.js';\nimport { looksLikeDate, looksLikeDateTime, numberByName, stringByName, type RecordContext } from './heuristics.js';\n\nexport interface GenerateOptions {\n /** Global seed; the same seed + key always yields the same value. */\n seed?: number;\n /** Distinguishes values under one seed, e.g. `GET /users/42 200`. */\n key?: string;\n /** Recursion limit for circular schemas. */\n maxDepth?: number;\n}\n\n// Faker's date helpers default to \"now\"; pin them so output never drifts.\nconst REF_DATE = new Date('2026-01-01T00:00:00.000Z');\n\n// The package root loads every locale (~23 MB of RSS); the `locale/en` entry only\n// exports a shared instance, so build a private one from its class and definitions.\nconst FakerClass = enFaker.constructor as typeof Faker;\nconst faker = new FakerClass({ locale: enFaker.rawDefinitions });\nfaker.setDefaultRefDate(REF_DATE);\n\n// Filling every optional field of every nested object explodes on big specs (Stripe\n// objects nest dozens of expandable objects). Past this depth, or once this many\n// values have been generated, only required fields and minItems are filled.\n// 250 keeps a Stripe list page of 10 full records near 15 ms (the target is 20 ms\n// p95) while every top-level field of a record is still present.\nconst RICH_DEPTH = 3;\nconst VALUE_BUDGET = 250;\n\ninterface Ctx {\n depth: number;\n maxDepth: number;\n /** Shared across one `generate` call. */\n budget: { values: number };\n /** Only required fields, e.g. to tell apart overlapping `oneOf` branches. */\n minimal?: boolean;\n name?: string;\n record?: RecordContext;\n}\n\n/** Generate a realistic, deterministic value that satisfies `schema`. */\nexport function generate(schema: Schema | undefined, opts: GenerateOptions = {}): unknown {\n faker.seed(hash(`${opts.seed ?? 1}:${opts.key ?? ''}`));\n return gen(schema ?? {}, { depth: 0, maxDepth: opts.maxDepth ?? 8, budget: { values: VALUE_BUDGET } });\n}\n\nfunction gen(schema: Schema, ctx: Ctx): unknown {\n // Real examples beat fake data, unless the spec's example contradicts its own schema.\n if (schema.example !== undefined && fits(schema.example, schema)) return structuredClone(schema.example);\n const example = Array.isArray(schema.examples) ? schema.examples.find((e: unknown) => fits(e, schema)) : undefined;\n if (example !== undefined) return structuredClone(example);\n if ('const' in schema) return schema.const;\n if (Array.isArray(schema.enum) && schema.enum.length) {\n // Specs sometimes list enum values their own pattern or maxLength rejects.\n const { enum: values, ...rest } = schema;\n const valid = values.filter((v: unknown) => v !== null && fits(v, rest));\n const options = valid.length ? valid : values.filter((v: unknown) => v !== null);\n return faker.helpers.arrayElement(options.length ? options : values);\n }\n\n if (Array.isArray(schema.allOf)) return gen(mergeAllOf(schema), ctx);\n const choices: Schema[] | undefined = schema.oneOf ?? schema.anyOf;\n if (Array.isArray(choices) && choices.length) return genChoice(schema, choices, Array.isArray(schema.oneOf), ctx);\n\n switch (typeOf(schema)) {\n case 'null':\n return null;\n case 'object':\n return genObject(schema, ctx);\n case 'array':\n return genArray(schema, ctx);\n case 'integer':\n return genNumber(schema, ctx, true);\n case 'number':\n return genNumber(schema, ctx, false);\n case 'boolean':\n return faker.datatype.boolean();\n case 'string':\n return genString(schema, ctx);\n default:\n return faker.word.noun();\n }\n}\n\n/**\n * Optional fields real APIs only fill when the client asks (HAL's `_embedded` via\n * `?expand=`). Generating them makes every record several times larger than the real\n * thing. Required ones are still filled.\n */\nconst ON_REQUEST = new Set(['_embedded']);\n\nfunction lean(ctx: Ctx): boolean {\n return ctx.minimal === true || ctx.depth > RICH_DEPTH || ctx.budget.values <= 0;\n}\n\n/**\n * Pick a `oneOf`/`anyOf` branch and generate from it. Branches often overlap (two\n * object shapes with no required fields both accept `{}`), so each candidate is\n * checked: it must satisfy its branch, and for `oneOf` no other branch.\n */\nfunction genChoice(schema: Schema, choices: Schema[], exclusive: boolean, ctx: Ctx): unknown {\n const rest = choiceBase(schema);\n const disc = discriminatorOf(schema);\n if (disc) return genDiscriminated(rest, disc, ctx);\n // Deep in the tree, prefer the cheapest branch (`string` over an expanded object).\n const order = lean(ctx) ? [...choices].sort((a, b) => cost(a) - cost(b)) : faker.helpers.shuffle([...choices]);\n let fallback: unknown;\n // A rejected candidate must not eat the budget of the next one, or later\n // candidates come out bare and match every branch.\n const budget = ctx.budget.values;\n // Second pass: a full object often satisfies a loose sibling branch too, while\n // the bare required fields of the same branch don't.\n for (const attempt of [ctx, { ...ctx, minimal: true }]) {\n for (const branch of order.slice(0, 4)) {\n const s = Object.keys(rest).length ? mergeBranch(rest, branch) : branch;\n ctx.budget.values = budget;\n const value = gen(s, attempt);\n if (fallback === undefined) fallback = value;\n if (!fits(value, s)) continue;\n if (exclusive && choices.length > 1 && countMatches(value, choices, 0, 2) !== 1) continue;\n return value;\n }\n if (!exclusive) break;\n }\n return fallback;\n}\n\n/** With a discriminator the branch is chosen by value, and the record carries that value. */\nfunction genDiscriminated(rest: Schema, disc: Discriminator, ctx: Ctx): unknown {\n const shared = Object.keys(rest).length > 0;\n const branchOf = (m: Discriminator['mapping'][number]) => (shared ? mergeBranch(rest, m.schema) : m.schema);\n // Skip mapping values the branch's own property schema rejects (a spec bug, but common).\n const usable = disc.mapping.filter((m) => {\n const s = branchOf(m);\n const prop = (s.allOf ? mergeAllOf(s) : s).properties?.[disc.property];\n return !prop || fits(m.value, prop);\n });\n const entry = faker.helpers.arrayElement(usable.length ? usable : disc.mapping);\n const value = gen(branchOf(entry), ctx);\n if (value && typeof value === 'object' && !Array.isArray(value)) (value as Record<string, unknown>)[disc.property] = entry.value;\n return value;\n}\n\n// Per-schema derived data, cached by identity: schemas never change, records repeat.\nconst baseCache = new WeakMap<Schema, Schema>();\nconst siblingCache = new WeakMap<Record<string, Schema>, Set<string>>();\n\n/** A oneOf/anyOf schema minus its alternatives: what every branch is merged with. */\nfunction choiceBase(schema: Schema): Schema {\n let base = baseCache.get(schema);\n if (!base) {\n const { oneOf, anyOf, discriminator, ...rest } = schema;\n baseCache.set(schema, (base = rest));\n }\n return base;\n}\n\nfunction siblingsOf(props: Record<string, Schema>): Set<string> {\n let set = siblingCache.get(props);\n if (!set) siblingCache.set(props, (set = new Set(Object.keys(props).map((k) => k.toLowerCase()))));\n return set;\n}\n\nfunction cost(s: Schema): number {\n if (s.enum || 'const' in s) return 0;\n const t = typeOf(s);\n if (t === 'object') return 2 + (s.required?.length ?? 0);\n if (t === 'array') return 2 + (s.minItems ?? 0);\n if (s.allOf || s.oneOf || s.anyOf) return 3;\n return t ? 1 : 3;\n}\n\nfunction genObject(schema: Schema, ctx: Ctx): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n if (ctx.depth >= ctx.maxDepth) return out;\n\n const props: Record<string, Schema> = schema.properties ?? {};\n const required = new Set<string>(schema.required ?? []);\n const record: RecordContext = { siblings: siblingsOf(props), owner: ctx.name };\n for (const [name, propSchema] of Object.entries(props)) {\n if (propSchema.writeOnly) continue;\n if (!required.has(name) && (lean(ctx) || ON_REQUEST.has(name))) continue;\n ctx.budget.values--;\n out[name] = gen(propSchema, { ...ctx, depth: ctx.depth + 1, name, record });\n }\n\n // Required keys the schema never describes still have to be present.\n const extra = typeof schema.additionalProperties === 'object' ? schema.additionalProperties : {};\n for (const name of required) {\n if (!(name in out) && !props[name]?.writeOnly) out[name] = gen(extra, { ...ctx, depth: ctx.depth + 1, name, record });\n }\n\n if (!schema.properties && schema.additionalProperties && typeof schema.additionalProperties === 'object' && !lean(ctx)) {\n const count = faker.number.int({ min: 1, max: 3 });\n for (let i = 0; i < count; i++) {\n out[faker.word.noun()] = gen(schema.additionalProperties, { ...ctx, depth: ctx.depth + 1, name: undefined });\n }\n }\n return out;\n}\n\nfunction genArray(schema: Schema, ctx: Ctx): unknown[] {\n const min = schema.minItems ?? 0;\n if (ctx.depth >= ctx.maxDepth) return [];\n // Nested arrays multiply (a list of invoices of line items of taxes): keep inner ones short.\n const max = Math.max(min, schema.maxItems ?? Math.max(min, ctx.depth > 1 ? 3 : 5));\n const count = lean(ctx) ? min : faker.number.int({ min: Math.max(min, Math.min(2, max)), max });\n const items: Schema = schema.items ?? {};\n // Items of a `users` array are users, so keep the singular name as the hint.\n const name = ctx.name?.replace(/ies$/, 'y').replace(/(ss|x|sh|ch|us)es$/, '$1').replace(/([^s])s$/, '$1');\n const out: unknown[] = [];\n const seen = new Set<string>();\n for (let attempts = 0; out.length < count && attempts < count * 5; attempts++) {\n const value = gen(items, { ...ctx, depth: ctx.depth + 1, name, record: undefined });\n if (schema.uniqueItems) {\n const k = JSON.stringify(value);\n if (seen.has(k)) continue;\n seen.add(k);\n }\n out.push(value);\n }\n return out;\n}\n\nfunction genNumber(schema: Schema, ctx: Ctx, integer: boolean): number {\n let lo = schema.minimum ?? -Infinity;\n let hi = schema.maximum ?? Infinity;\n // 3.0 uses booleans for exclusive bounds; 3.1 uses numbers.\n const step = integer ? 1 : 0.01;\n if (typeof schema.exclusiveMinimum === 'number') lo = Math.max(lo, schema.exclusiveMinimum + step);\n else if (schema.exclusiveMinimum === true) lo += step;\n if (typeof schema.exclusiveMaximum === 'number') hi = Math.min(hi, schema.exclusiveMaximum - step);\n else if (schema.exclusiveMaximum === true) hi -= step;\n\n const hinted = ctx.name ? numberByName(faker, ctx.name, integer || schema.format === 'int64' || schema.format === 'int32') : undefined;\n let value: number;\n if (hinted !== undefined && hinted >= lo && hinted <= hi) {\n value = hinted;\n } else {\n const min = Number.isFinite(lo) ? lo : Number.isFinite(hi) ? hi - 1000 : 0;\n const max = Number.isFinite(hi) ? hi : min + 1000;\n value = integer\n ? faker.number.int({ min: Math.ceil(min), max: Math.floor(max) })\n : faker.number.float({ min, max, fractionDigits: 2 });\n }\n\n if (schema.multipleOf) {\n const m = schema.multipleOf;\n let snapped = Math.round(value / m) * m;\n if (snapped < lo) snapped += m;\n if (snapped > hi) snapped -= m;\n value = Number(snapped.toFixed(10));\n }\n if (integer) value = Math.round(value);\n return value;\n}\n\nfunction genString(schema: Schema, ctx: Ctx): string {\n const rec = ctx.record ?? { siblings: new Set<string>() };\n // `avatarUrl: {format: uri}` should still be an avatar, and `email` should match `firstName`.\n const named = ctx.name && NAMED_FORMATS.has(schema.format) ? namedFormat(schema.format, stringByName(faker, ctx.name, rec, schema)) : undefined;\n let value = named ?? byFormat(schema.format) ?? byPattern(schema.pattern);\n if (value === undefined && ctx.name) {\n if (looksLikeDate(ctx.name)) value = isoDate(faker.date.birthdate());\n else if (looksLikeDateTime(ctx.name)) value = faker.date.past({ years: 2 }).toISOString();\n else value = stringByName(faker, ctx.name, rec, schema);\n }\n value ??= faker.lorem.words({ min: 1, max: 3 });\n\n if (schema.format || schema.pattern) return value;\n const min = schema.minLength ?? 0;\n const max = schema.maxLength ?? Infinity;\n while (value.length < min) value += faker.string.alpha({ length: min - value.length, casing: 'lower' });\n if (value.length > max) value = value.slice(0, max);\n return value;\n}\n\n/** Formats where a name-based value (an avatar URL, a matching email) beats a generic one. */\nconst NAMED_FORMATS = new Set(['email', 'idn-email', 'uri', 'url', 'iri']);\n\n/** Keep a name-based value when it also satisfies the generic format. */\nfunction namedFormat(format: string | undefined, candidate: string | undefined): string | undefined {\n if (candidate === undefined) return undefined;\n if (format === 'email' || format === 'idn-email') return /^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$/.test(candidate) ? candidate : undefined;\n if (format === 'uri' || format === 'url' || format === 'iri') return URL.canParse(candidate) ? candidate : undefined;\n return undefined;\n}\n\nfunction byFormat(format: string | undefined): string | undefined {\n switch (format) {\n case 'email':\n case 'idn-email':\n return faker.internet.email().toLowerCase();\n case 'uri':\n case 'url':\n case 'iri':\n return faker.internet.url();\n case 'uri-reference':\n return `/${faker.lorem.slug(2)}`;\n case 'uuid':\n return faker.string.uuid();\n case 'date':\n return isoDate(faker.date.past({ years: 2 }));\n case 'date-time':\n return faker.date.past({ years: 2 }).toISOString();\n case 'time':\n return `${faker.date.past().toISOString().slice(11, 19)}Z`;\n case 'duration':\n return `PT${faker.number.int({ min: 1, max: 59 })}M`;\n case 'ipv4':\n return faker.internet.ipv4();\n case 'ipv6':\n return faker.internet.ipv6();\n case 'hostname':\n case 'idn-hostname':\n return faker.internet.domainName();\n case 'byte':\n return Buffer.from(faker.lorem.words(3)).toString('base64');\n case 'binary':\n return faker.string.alphanumeric(16);\n case 'password':\n return faker.internet.password({ length: 16 });\n case 'json-pointer':\n return `/${faker.word.noun()}/${faker.number.int(9)}`;\n case 'relative-json-pointer':\n return `0/${faker.word.noun()}`;\n case 'uri-template':\n return `https://${faker.internet.domainName()}/items/{id}`;\n case 'iri-reference':\n return `/${faker.lorem.slug(2)}`;\n case 'regex':\n return '^[a-z0-9-]+$';\n default:\n return undefined;\n }\n}\n\nfunction byPattern(pattern: string | undefined): string | undefined {\n if (!pattern) return undefined;\n const compiled = patternGenerator(pattern);\n if (!compiled) return undefined;\n for (let i = 0; i < 10; i++) {\n const candidate = compiled.gen.gen();\n if (compiled.re.test(candidate)) return candidate;\n }\n return undefined;\n}\n\n// Compiling a RandExp per value dominated pattern-heavy specs; compile once per pattern.\n// Its randomness comes from the shared, reseeded faker, so reuse stays deterministic.\nconst patternCache = new Map<string, { re: RegExp; gen: RandExp } | null>();\n\nfunction patternGenerator(pattern: string): { re: RegExp; gen: RandExp } | null {\n let compiled = patternCache.get(pattern);\n if (compiled === undefined) {\n try {\n const gen = new RandExp(pattern);\n gen.max = 5; // Cap `*` and `+` so values stay short.\n gen.randInt = (min, max) => faker.number.int({ min, max });\n // Keep generated characters printable ASCII unless the pattern says otherwise.\n gen.defaultRange.subtract(0, 31);\n gen.defaultRange.subtract(127, 65535);\n compiled = { re: new RegExp(pattern, 'u'), gen };\n } catch {\n compiled = null; // Unsupported regex features fall through to a plain string.\n }\n patternCache.set(pattern, compiled);\n }\n return compiled;\n}\n\nfunction isoDate(d: Date): string {\n return d.toISOString().slice(0, 10);\n}\n\n/** 32-bit FNV-1a; stable across platforms and Node versions. */\nexport function hash(input: string): number {\n let h = 0x811c9dc5;\n for (let i = 0; i < input.length; i++) {\n h ^= input.charCodeAt(i);\n h = Math.imul(h, 0x01000193);\n }\n return h >>> 0;\n}\n"]}
@@ -0,0 +1,28 @@
1
+ import type { Faker } from '@faker-js/faker';
2
+ import type { Schema } from './model.js';
3
+ /** Per-object context so a record's name, username, email and avatar agree with each other. */
4
+ export interface RecordContext {
5
+ /** Property names of the object being generated. */
6
+ siblings: Set<string>;
7
+ /** Name of the property holding this object, e.g. `team` for `team.name`. */
8
+ owner?: string;
9
+ person?: {
10
+ first: string;
11
+ last: string;
12
+ };
13
+ }
14
+ export declare function personOf(faker: Faker, rec: RecordContext): {
15
+ first: string;
16
+ last: string;
17
+ };
18
+ /** Normalize `created_at`, `createdAt`, `Created-At` to `createdat`. */
19
+ export declare function normalizeName(name: string): string;
20
+ /** A realistic string for this property name, or undefined when no rule applies. */
21
+ export declare function stringByName(f: Faker, name: string, rec: RecordContext, schema: Schema): string | undefined;
22
+ /** Whether a string property name implies a timestamp when the schema gives no `format`. */
23
+ export declare function looksLikeDateTime(name: string): boolean;
24
+ /** `id`, `userId`, `user_id`, `uuid` — but not `paid` or `valid`. */
25
+ export declare function isIdName(name: string): boolean;
26
+ export declare function looksLikeDate(name: string): boolean;
27
+ /** A realistic number for this property name, or undefined when no rule applies. */
28
+ export declare function numberByName(f: Faker, name: string, integer: boolean): number | undefined;
@@ -0,0 +1,139 @@
1
+ export function personOf(faker, rec) {
2
+ rec.person ??= { first: faker.person.firstName(), last: faker.person.lastName() };
3
+ return rec.person;
4
+ }
5
+ /** Normalize `created_at`, `createdAt`, `Created-At` to `createdat`. */
6
+ export function normalizeName(name) {
7
+ return name.toLowerCase().replace(/[^a-z0-9]/g, '');
8
+ }
9
+ const has = (rec, ...names) => names.some((n) => rec.siblings.has(n));
10
+ const STRING_RULES = [
11
+ [/^(firstname|givenname|forename)$/, (f, r) => personOf(f, r).first],
12
+ [/^(lastname|surname|familyname)$/, (f, r) => personOf(f, r).last],
13
+ [/^(fullname|displayname|author|authorname|ownername|customername|contactname)$/, (f, r) => fullName(f, r)],
14
+ [
15
+ /^name$/,
16
+ (f, r) => {
17
+ const owner = normalizeName(r.owner ?? '');
18
+ if (/(product|item|sku)$/.test(owner) || has(r, 'price', 'sku', 'cost', 'stock', 'inventory'))
19
+ return f.commerce.productName();
20
+ if (/(team|group|department|squad|unit)$/.test(owner))
21
+ return `${f.word.adjective()} ${f.word.noun()}`.replace(/^\w/, (c) => c.toUpperCase());
22
+ if (/(org|organization|organisation|company|employer|account|workspace|tenant|vendor|brand)$/.test(owner))
23
+ return f.company.name();
24
+ if (/(project|repo|repository|app|application|service)$/.test(owner))
25
+ return f.lorem.slug(2);
26
+ if (/(category|tag|label|genre|topic)$/.test(owner))
27
+ return f.commerce.department();
28
+ if (has(r, 'domain', 'industry', 'employees', 'website'))
29
+ return f.company.name();
30
+ return fullName(f, r);
31
+ },
32
+ ],
33
+ [/^(username|login|handle|nickname|screenname)$/, (f, r) => username(f, r)],
34
+ [/email/, (f, r) => email(f, r)],
35
+ [/(phone|mobile|telephone|^tel$|fax)/, (f) => f.phone.number({ style: 'international' })],
36
+ [/(avatar|profileimage|profilepicture|profilephoto)/, (f) => f.image.avatar()],
37
+ [/(image|photo|picture|thumbnail|logo|banner|cover)(url)?$/, (f) => f.image.url({ width: 640, height: 480 })],
38
+ [/(url|uri|website|homepage|link|href)$/, (f) => f.internet.url()],
39
+ [/^(company|companyname|organization|organisation|employer)$/, (f) => f.company.name()],
40
+ [/^(jobtitle|position|role|occupation)$/, (f) => f.person.jobTitle()],
41
+ [/^(street|streetaddress|address|addressline1?|line1)$/, (f) => f.location.streetAddress()],
42
+ [/^(addressline2|line2)$/, (f) => f.location.secondaryAddress()],
43
+ [/^(city|town)$/, (f) => f.location.city()],
44
+ [/^state$/, (f, r) => (has(r, 'city', 'zip', 'zipcode', 'postcode', 'postalcode', 'country') ? f.location.state() : f.helpers.arrayElement(['active', 'pending', 'inactive']))],
45
+ [/^(province|region)$/, (f) => f.location.state()],
46
+ [/^(zip|zipcode|postcode|postalcode)$/, (f) => f.location.zipCode()],
47
+ [/^(countrycode|countryiso)$/, (f) => f.location.countryCode()],
48
+ [/^country$/, (f) => f.location.country()],
49
+ [/^(timezone|tz)$/, (f) => f.location.timeZone()],
50
+ [/^(currency|currencycode)$/, (f) => f.finance.currencyCode()],
51
+ [/^(locale|language|lang)$/, (f) => f.helpers.arrayElement(['en-US', 'en-GB', 'de-DE', 'fr-FR', 'es-ES', 'ja-JP'])],
52
+ [/(color|colour)$/, (f) => f.color.human()],
53
+ [/^(hex|hexcolor)$/, (f) => f.color.rgb()],
54
+ [/^slug$/, (f) => f.lorem.slug(3)],
55
+ [/^sku$/, (f) => f.string.alphanumeric({ length: 8, casing: 'upper' })],
56
+ [/^(ip|ipaddress|ipv4)$/, (f) => f.internet.ipv4()],
57
+ [/^ipv6$/, (f) => f.internet.ipv6()],
58
+ [/^(domain|hostname|host)$/, (f) => f.internet.domainName()],
59
+ [/^(useragent)$/, (f) => f.internet.userAgent()],
60
+ [/^(password|secret)$/, (f) => f.internet.password({ length: 16 })],
61
+ [/^(title|headline|subject)$/, (f) => sentence(f.lorem.sentence({ min: 3, max: 7 }))],
62
+ [/^(description|summary|bio|about|excerpt)$/, (f) => f.lorem.sentences({ min: 1, max: 3 })],
63
+ [/^(body|content|text|comment|message|note|notes)$/, (f) => f.lorem.paragraph()],
64
+ [/^status$/, (f) => f.helpers.arrayElement(['active', 'pending', 'inactive'])],
65
+ [/^(type|kind|category)$/, (f) => f.commerce.department().toLowerCase()],
66
+ [/^(tag|label)$/, (f) => f.word.noun()],
67
+ [/^(token|accesstoken|refreshtoken|apikey)$/, (f) => f.string.alphanumeric(32)],
68
+ ];
69
+ /** A realistic string for this property name, or undefined when no rule applies. */
70
+ export function stringByName(f, name, rec, schema) {
71
+ if (isIdName(name))
72
+ return f.string.uuid();
73
+ const rule = ruleFor(name);
74
+ return rule ? rule(f, rec, schema) : undefined;
75
+ }
76
+ // Field names repeat endlessly (every record has an `email`), so remember which
77
+ // rule each name hits instead of running ~40 regexes per string.
78
+ const ruleCache = new Map();
79
+ function ruleFor(name) {
80
+ let rule = ruleCache.get(name);
81
+ if (rule === undefined) {
82
+ const n = normalizeName(name);
83
+ rule = STRING_RULES.find(([re]) => re.test(n))?.[1] ?? null;
84
+ ruleCache.set(name, rule);
85
+ }
86
+ return rule;
87
+ }
88
+ /** Whether a string property name implies a timestamp when the schema gives no `format`. */
89
+ export function looksLikeDateTime(name) {
90
+ return /^(timestamp|datetime|time|date)$/i.test(name) || /([a-z0-9](At|On|Date|Time|Timestamp)|_(at|on|date|time|timestamp))$/.test(name);
91
+ }
92
+ /** `id`, `userId`, `user_id`, `uuid` — but not `paid` or `valid`. */
93
+ export function isIdName(name) {
94
+ return /^(id|uuid|guid)$/i.test(name) || /([a-z0-9](Id|ID|Uuid)|[_-](id|uuid))$/.test(name);
95
+ }
96
+ export function looksLikeDate(name) {
97
+ const n = normalizeName(name);
98
+ return /(birthday|birthdate|dob|dateofbirth)$/.test(n) || /^(date|day)$/.test(n);
99
+ }
100
+ const NUMBER_RULES = [
101
+ [/(price|amount|cost|balance|salary|fee|subtotal|tax|revenue)$/, (f, int) => (int ? f.number.int({ min: 100, max: 100_000 }) : f.number.float({ min: 1, max: 1000, fractionDigits: 2 }))],
102
+ [/^age$/, (f) => f.number.int({ min: 18, max: 85 })],
103
+ [/^(lat|latitude)$/, (f) => f.location.latitude()],
104
+ [/^(lng|lon|long|longitude)$/, (f) => f.location.longitude()],
105
+ [/^(rating|stars|score)$/, (f, int) => (int ? f.number.int({ min: 1, max: 5 }) : f.number.float({ min: 1, max: 5, fractionDigits: 1 }))],
106
+ [/(percent|percentage|ratio)$/, (f, int) => (int ? f.number.int({ min: 0, max: 100 }) : f.number.float({ min: 0, max: 1, fractionDigits: 2 }))],
107
+ [/^(page|pagenumber|currentpage)$/, (f) => f.number.int({ min: 1, max: 5 })],
108
+ [/^(pagesize|perpage|limit|per)$/, (f) => f.helpers.arrayElement([10, 20, 25, 50])],
109
+ [/^(year)$/, (f) => f.number.int({ min: 1990, max: 2026 })],
110
+ [/(count|total|quantity|qty|stock|size|length|number)$/, (f) => f.number.int({ min: 0, max: 100 })],
111
+ ];
112
+ /** A realistic number for this property name, or undefined when no rule applies. */
113
+ export function numberByName(f, name, integer) {
114
+ if (isIdName(name))
115
+ return f.number.int({ min: 1, max: 10_000 });
116
+ if (integer && looksLikeDateTime(name))
117
+ return Math.floor(f.date.past({ years: 2 }).getTime() / 1000);
118
+ const n = normalizeName(name);
119
+ for (const [re, gen] of NUMBER_RULES)
120
+ if (re.test(n))
121
+ return gen(f, integer);
122
+ return undefined;
123
+ }
124
+ function fullName(f, r) {
125
+ const p = personOf(f, r);
126
+ return `${p.first} ${p.last}`;
127
+ }
128
+ function username(f, r) {
129
+ const p = personOf(f, r);
130
+ return f.internet.username({ firstName: p.first, lastName: p.last });
131
+ }
132
+ function email(f, r) {
133
+ const p = personOf(f, r);
134
+ return f.internet.email({ firstName: p.first, lastName: p.last }).toLowerCase();
135
+ }
136
+ function sentence(s) {
137
+ return s.replace(/\.$/, '');
138
+ }
139
+ //# sourceMappingURL=heuristics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heuristics.js","sourceRoot":"","sources":["../src/heuristics.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Faker } from '@faker-js/faker';\nimport type { Schema } from './model.js';\n\n/** Per-object context so a record's name, username, email and avatar agree with each other. */\nexport interface RecordContext {\n /** Property names of the object being generated. */\n siblings: Set<string>;\n /** Name of the property holding this object, e.g. `team` for `team.name`. */\n owner?: string;\n person?: { first: string; last: string };\n}\n\nexport function personOf(faker: Faker, rec: RecordContext) {\n rec.person ??= { first: faker.person.firstName(), last: faker.person.lastName() };\n return rec.person;\n}\n\n/** Normalize `created_at`, `createdAt`, `Created-At` to `createdat`. */\nexport function normalizeName(name: string): string {\n return name.toLowerCase().replace(/[^a-z0-9]/g, '');\n}\n\ntype StringRule = [RegExp, (f: Faker, rec: RecordContext, schema: Schema) => string];\n\nconst has = (rec: RecordContext, ...names: string[]) => names.some((n) => rec.siblings.has(n));\n\nconst STRING_RULES: StringRule[] = [\n [/^(firstname|givenname|forename)$/, (f, r) => personOf(f, r).first],\n [/^(lastname|surname|familyname)$/, (f, r) => personOf(f, r).last],\n [/^(fullname|displayname|author|authorname|ownername|customername|contactname)$/, (f, r) => fullName(f, r)],\n [\n /^name$/,\n (f, r) => {\n const owner = normalizeName(r.owner ?? '');\n if (/(product|item|sku)$/.test(owner) || has(r, 'price', 'sku', 'cost', 'stock', 'inventory')) return f.commerce.productName();\n if (/(team|group|department|squad|unit)$/.test(owner)) return `${f.word.adjective()} ${f.word.noun()}`.replace(/^\\w/, (c) => c.toUpperCase());\n if (/(org|organization|organisation|company|employer|account|workspace|tenant|vendor|brand)$/.test(owner)) return f.company.name();\n if (/(project|repo|repository|app|application|service)$/.test(owner)) return f.lorem.slug(2);\n if (/(category|tag|label|genre|topic)$/.test(owner)) return f.commerce.department();\n if (has(r, 'domain', 'industry', 'employees', 'website')) return f.company.name();\n return fullName(f, r);\n },\n ],\n [/^(username|login|handle|nickname|screenname)$/, (f, r) => username(f, r)],\n [/email/, (f, r) => email(f, r)],\n [/(phone|mobile|telephone|^tel$|fax)/, (f) => f.phone.number({ style: 'international' })],\n [/(avatar|profileimage|profilepicture|profilephoto)/, (f) => f.image.avatar()],\n [/(image|photo|picture|thumbnail|logo|banner|cover)(url)?$/, (f) => f.image.url({ width: 640, height: 480 })],\n [/(url|uri|website|homepage|link|href)$/, (f) => f.internet.url()],\n [/^(company|companyname|organization|organisation|employer)$/, (f) => f.company.name()],\n [/^(jobtitle|position|role|occupation)$/, (f) => f.person.jobTitle()],\n [/^(street|streetaddress|address|addressline1?|line1)$/, (f) => f.location.streetAddress()],\n [/^(addressline2|line2)$/, (f) => f.location.secondaryAddress()],\n [/^(city|town)$/, (f) => f.location.city()],\n [/^state$/, (f, r) => (has(r, 'city', 'zip', 'zipcode', 'postcode', 'postalcode', 'country') ? f.location.state() : f.helpers.arrayElement(['active', 'pending', 'inactive']))],\n [/^(province|region)$/, (f) => f.location.state()],\n [/^(zip|zipcode|postcode|postalcode)$/, (f) => f.location.zipCode()],\n [/^(countrycode|countryiso)$/, (f) => f.location.countryCode()],\n [/^country$/, (f) => f.location.country()],\n [/^(timezone|tz)$/, (f) => f.location.timeZone()],\n [/^(currency|currencycode)$/, (f) => f.finance.currencyCode()],\n [/^(locale|language|lang)$/, (f) => f.helpers.arrayElement(['en-US', 'en-GB', 'de-DE', 'fr-FR', 'es-ES', 'ja-JP'])],\n [/(color|colour)$/, (f) => f.color.human()],\n [/^(hex|hexcolor)$/, (f) => f.color.rgb()],\n [/^slug$/, (f) => f.lorem.slug(3)],\n [/^sku$/, (f) => f.string.alphanumeric({ length: 8, casing: 'upper' })],\n [/^(ip|ipaddress|ipv4)$/, (f) => f.internet.ipv4()],\n [/^ipv6$/, (f) => f.internet.ipv6()],\n [/^(domain|hostname|host)$/, (f) => f.internet.domainName()],\n [/^(useragent)$/, (f) => f.internet.userAgent()],\n [/^(password|secret)$/, (f) => f.internet.password({ length: 16 })],\n [/^(title|headline|subject)$/, (f) => sentence(f.lorem.sentence({ min: 3, max: 7 }))],\n [/^(description|summary|bio|about|excerpt)$/, (f) => f.lorem.sentences({ min: 1, max: 3 })],\n [/^(body|content|text|comment|message|note|notes)$/, (f) => f.lorem.paragraph()],\n [/^status$/, (f) => f.helpers.arrayElement(['active', 'pending', 'inactive'])],\n [/^(type|kind|category)$/, (f) => f.commerce.department().toLowerCase()],\n [/^(tag|label)$/, (f) => f.word.noun()],\n [/^(token|accesstoken|refreshtoken|apikey)$/, (f) => f.string.alphanumeric(32)],\n];\n\n/** A realistic string for this property name, or undefined when no rule applies. */\nexport function stringByName(f: Faker, name: string, rec: RecordContext, schema: Schema): string | undefined {\n if (isIdName(name)) return f.string.uuid();\n const rule = ruleFor(name);\n return rule ? rule(f, rec, schema) : undefined;\n}\n\n// Field names repeat endlessly (every record has an `email`), so remember which\n// rule each name hits instead of running ~40 regexes per string.\nconst ruleCache = new Map<string, StringRule[1] | null>();\n\nfunction ruleFor(name: string): StringRule[1] | null {\n let rule = ruleCache.get(name);\n if (rule === undefined) {\n const n = normalizeName(name);\n rule = STRING_RULES.find(([re]) => re.test(n))?.[1] ?? null;\n ruleCache.set(name, rule);\n }\n return rule;\n}\n\n/** Whether a string property name implies a timestamp when the schema gives no `format`. */\nexport function looksLikeDateTime(name: string): boolean {\n return /^(timestamp|datetime|time|date)$/i.test(name) || /([a-z0-9](At|On|Date|Time|Timestamp)|_(at|on|date|time|timestamp))$/.test(name);\n}\n\n/** `id`, `userId`, `user_id`, `uuid` — but not `paid` or `valid`. */\nexport function isIdName(name: string): boolean {\n return /^(id|uuid|guid)$/i.test(name) || /([a-z0-9](Id|ID|Uuid)|[_-](id|uuid))$/.test(name);\n}\n\nexport function looksLikeDate(name: string): boolean {\n const n = normalizeName(name);\n return /(birthday|birthdate|dob|dateofbirth)$/.test(n) || /^(date|day)$/.test(n);\n}\n\ntype NumberRule = [RegExp, (f: Faker, integer: boolean) => number];\n\nconst NUMBER_RULES: NumberRule[] = [\n [/(price|amount|cost|balance|salary|fee|subtotal|tax|revenue)$/, (f, int) => (int ? f.number.int({ min: 100, max: 100_000 }) : f.number.float({ min: 1, max: 1000, fractionDigits: 2 }))],\n [/^age$/, (f) => f.number.int({ min: 18, max: 85 })],\n [/^(lat|latitude)$/, (f) => f.location.latitude()],\n [/^(lng|lon|long|longitude)$/, (f) => f.location.longitude()],\n [/^(rating|stars|score)$/, (f, int) => (int ? f.number.int({ min: 1, max: 5 }) : f.number.float({ min: 1, max: 5, fractionDigits: 1 }))],\n [/(percent|percentage|ratio)$/, (f, int) => (int ? f.number.int({ min: 0, max: 100 }) : f.number.float({ min: 0, max: 1, fractionDigits: 2 }))],\n [/^(page|pagenumber|currentpage)$/, (f) => f.number.int({ min: 1, max: 5 })],\n [/^(pagesize|perpage|limit|per)$/, (f) => f.helpers.arrayElement([10, 20, 25, 50])],\n [/^(year)$/, (f) => f.number.int({ min: 1990, max: 2026 })],\n [/(count|total|quantity|qty|stock|size|length|number)$/, (f) => f.number.int({ min: 0, max: 100 })],\n];\n\n/** A realistic number for this property name, or undefined when no rule applies. */\nexport function numberByName(f: Faker, name: string, integer: boolean): number | undefined {\n if (isIdName(name)) return f.number.int({ min: 1, max: 10_000 });\n if (integer && looksLikeDateTime(name)) return Math.floor(f.date.past({ years: 2 }).getTime() / 1000);\n const n = normalizeName(name);\n for (const [re, gen] of NUMBER_RULES) if (re.test(n)) return gen(f, integer);\n return undefined;\n}\n\nfunction fullName(f: Faker, r: RecordContext) {\n const p = personOf(f, r);\n return `${p.first} ${p.last}`;\n}\n\nfunction username(f: Faker, r: RecordContext) {\n const p = personOf(f, r);\n return f.internet.username({ firstName: p.first, lastName: p.last });\n}\n\nfunction email(f: Faker, r: RecordContext) {\n const p = personOf(f, r);\n return f.internet.email({ firstName: p.first, lastName: p.last }).toLowerCase();\n}\n\nfunction sentence(s: string) {\n return s.replace(/\\.$/, '');\n}\n"]}
@@ -0,0 +1,22 @@
1
+ import { type MockServer, type MockServerOptions } from './server.js';
2
+ export { generate, type GenerateOptions } from './generate.js';
3
+ export type { MockModel, MockResponse, MockRoute, Schema } from './model.js';
4
+ export { inferSchema, SchemaInferrer } from './infer.js';
5
+ export { loadSource } from './load.js';
6
+ export { loadOpenApi, SpecLoadError } from './openapi.js';
7
+ export { formatOpenApi, loadSamples, parseSampleName, toOpenApi } from './samples.js';
8
+ export { ResponseValidator, toJsonSchema, type ValidationResult } from './validate.js';
9
+ export { respond, type MockResult, type MockServer, type MockServerOptions, type RespondInput } from './server.js';
10
+ /**
11
+ * Create a mock server from a spec path, a sample folder, or an already-loaded model.
12
+ *
13
+ * ```ts
14
+ * const mock = await createMockServer({ spec: './openapi.yaml' });
15
+ * const url = await mock.listen(0);
16
+ * ```
17
+ */
18
+ export declare function createMockServer(options: Omit<MockServerOptions, 'model'> & ({
19
+ spec: string;
20
+ } | {
21
+ model: MockServerOptions['model'];
22
+ })): Promise<MockServer>;
package/dist/index.js ADDED
@@ -0,0 +1,22 @@
1
+ import { loadSource } from './load.js';
2
+ import { createMockServer as createServer } from './server.js';
3
+ export { generate } from './generate.js';
4
+ export { inferSchema, SchemaInferrer } from './infer.js';
5
+ export { loadSource } from './load.js';
6
+ export { loadOpenApi, SpecLoadError } from './openapi.js';
7
+ export { formatOpenApi, loadSamples, parseSampleName, toOpenApi } from './samples.js';
8
+ export { ResponseValidator, toJsonSchema } from './validate.js';
9
+ export { respond } from './server.js';
10
+ /**
11
+ * Create a mock server from a spec path, a sample folder, or an already-loaded model.
12
+ *
13
+ * ```ts
14
+ * const mock = await createMockServer({ spec: './openapi.yaml' });
15
+ * const url = await mock.listen(0);
16
+ * ```
17
+ */
18
+ export async function createMockServer(options) {
19
+ const model = 'model' in options ? options.model : await loadSource(options.spec);
20
+ return createServer({ ...options, model });
21
+ }
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,gBAAgB,IAAI,YAAY,EAA2C,MAAM,aAAa,CAAC;AAExG,OAAO,EAAE,QAAQ,EAAwB,MAAM,eAAe,CAAC;AAE/D,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACtF,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAyB,MAAM,eAAe,CAAC;AACvF,OAAO,EAAE,OAAO,EAA+E,MAAM,aAAa,CAAC;AAEnH;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,OAAsG;IAEtG,MAAM,KAAK,GAAG,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAClF,OAAO,YAAY,CAAC,EAAE,GAAG,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;AAC7C,CAAC","sourcesContent":["import { loadSource } from './load.js';\nimport { createMockServer as createServer, type MockServer, type MockServerOptions } from './server.js';\n\nexport { generate, type GenerateOptions } from './generate.js';\nexport type { MockModel, MockResponse, MockRoute, Schema } from './model.js';\nexport { inferSchema, SchemaInferrer } from './infer.js';\nexport { loadSource } from './load.js';\nexport { loadOpenApi, SpecLoadError } from './openapi.js';\nexport { formatOpenApi, loadSamples, parseSampleName, toOpenApi } from './samples.js';\nexport { ResponseValidator, toJsonSchema, type ValidationResult } from './validate.js';\nexport { respond, type MockResult, type MockServer, type MockServerOptions, type RespondInput } from './server.js';\n\n/**\n * Create a mock server from a spec path, a sample folder, or an already-loaded model.\n *\n * ```ts\n * const mock = await createMockServer({ spec: './openapi.yaml' });\n * const url = await mock.listen(0);\n * ```\n */\nexport async function createMockServer(\n options: Omit<MockServerOptions, 'model'> & ({ spec: string } | { model: MockServerOptions['model'] }),\n): Promise<MockServer> {\n const model = 'model' in options ? options.model : await loadSource(options.spec);\n return createServer({ ...options, model });\n}\n"]}
@@ -0,0 +1,10 @@
1
+ import type { Schema } from './model.js';
2
+ /** Collects samples for one schema position. Call `add` per sample, then `schema()`. */
3
+ export declare class SchemaInferrer {
4
+ private acc;
5
+ add(value: unknown): this;
6
+ get samples(): number;
7
+ schema(): Schema;
8
+ }
9
+ /** Infer a JSON Schema (OpenAPI 3.1 dialect) that every one of `samples` validates against. */
10
+ export declare function inferSchema(...samples: unknown[]): Schema;
package/dist/infer.js ADDED
@@ -0,0 +1,166 @@
1
+ // Schema inference works in two passes: `observe` folds every sample value into an
2
+ // accumulator of statistics, then `finalize` turns those statistics into a schema.
3
+ // Seeing all samples first is what lets us tell "optional" from "always present",
4
+ // "nullable" from "never null", and an enum from free text.
5
+ const MAX_TRACKED_VALUES = 50;
6
+ /** Keys whose values are free text even when the samples happen to repeat. */
7
+ const FREE_TEXT_KEY = /(name|title|description|summary|label|text|message|comment|bio|note|notes|body|content)$/i;
8
+ function emptyAcc() {
9
+ return {
10
+ seen: 0,
11
+ nulls: 0,
12
+ booleans: 0,
13
+ integers: 0,
14
+ floats: 0,
15
+ negative: false,
16
+ strings: 0,
17
+ stringValues: new Map(),
18
+ tooManyValues: false,
19
+ formats: new Map(),
20
+ arrays: 0,
21
+ objects: 0,
22
+ props: new Map(),
23
+ };
24
+ }
25
+ /** Collects samples for one schema position. Call `add` per sample, then `schema()`. */
26
+ export class SchemaInferrer {
27
+ acc = emptyAcc();
28
+ add(value) {
29
+ observe(this.acc, value);
30
+ return this;
31
+ }
32
+ get samples() {
33
+ return this.acc.seen;
34
+ }
35
+ schema() {
36
+ return finalize(this.acc);
37
+ }
38
+ }
39
+ /** Infer a JSON Schema (OpenAPI 3.1 dialect) that every one of `samples` validates against. */
40
+ export function inferSchema(...samples) {
41
+ const inferrer = new SchemaInferrer();
42
+ for (const s of samples)
43
+ inferrer.add(s);
44
+ return inferrer.schema();
45
+ }
46
+ function observe(acc, value) {
47
+ acc.seen++;
48
+ if (value === null || value === undefined) {
49
+ acc.nulls++;
50
+ }
51
+ else if (typeof value === 'boolean') {
52
+ acc.booleans++;
53
+ }
54
+ else if (typeof value === 'number') {
55
+ if (Number.isInteger(value))
56
+ acc.integers++;
57
+ else
58
+ acc.floats++;
59
+ if (value < 0)
60
+ acc.negative = true;
61
+ }
62
+ else if (typeof value === 'string') {
63
+ acc.strings++;
64
+ const format = detectFormat(value);
65
+ acc.formats.set(format, (acc.formats.get(format) ?? 0) + 1);
66
+ if (!acc.tooManyValues) {
67
+ acc.stringValues.set(value, (acc.stringValues.get(value) ?? 0) + 1);
68
+ if (acc.stringValues.size > MAX_TRACKED_VALUES) {
69
+ acc.tooManyValues = true;
70
+ acc.stringValues.clear();
71
+ }
72
+ }
73
+ }
74
+ else if (Array.isArray(value)) {
75
+ acc.arrays++;
76
+ acc.items ??= emptyAcc();
77
+ for (const item of value)
78
+ observe(acc.items, item);
79
+ }
80
+ else if (typeof value === 'object') {
81
+ acc.objects++;
82
+ for (const [key, v] of Object.entries(value)) {
83
+ let prop = acc.props.get(key);
84
+ if (!prop)
85
+ acc.props.set(key, (prop = emptyAcc()));
86
+ observe(prop, v);
87
+ }
88
+ }
89
+ }
90
+ function finalize(acc, key) {
91
+ const variants = [];
92
+ if (acc.objects)
93
+ variants.push(objectSchema(acc));
94
+ if (acc.arrays)
95
+ variants.push({ type: 'array', items: acc.items && acc.items.seen ? finalize(acc.items) : {} });
96
+ if (acc.strings)
97
+ variants.push(stringSchema(acc, key));
98
+ if (acc.integers || acc.floats) {
99
+ variants.push({ type: acc.floats ? 'number' : 'integer', ...(acc.negative ? {} : { minimum: 0 }) });
100
+ }
101
+ if (acc.booleans)
102
+ variants.push({ type: 'boolean' });
103
+ if (variants.length === 0)
104
+ return acc.nulls ? { type: 'null' } : {};
105
+ if (variants.length === 1) {
106
+ const only = variants[0];
107
+ if (acc.nulls) {
108
+ only.type = [only.type, 'null'];
109
+ if (only.enum)
110
+ only.enum = [...only.enum, null];
111
+ }
112
+ return only;
113
+ }
114
+ if (acc.nulls)
115
+ variants.push({ type: 'null' });
116
+ return { anyOf: variants };
117
+ }
118
+ function objectSchema(acc) {
119
+ const properties = {};
120
+ const required = [];
121
+ for (const [key, prop] of acc.props) {
122
+ properties[key] = finalize(prop, key);
123
+ if (prop.seen === acc.objects)
124
+ required.push(key);
125
+ }
126
+ return { type: 'object', properties, ...(required.length ? { required } : {}) };
127
+ }
128
+ function stringSchema(acc, key) {
129
+ const formats = [...acc.formats.keys()];
130
+ if (formats.length === 1 && formats[0])
131
+ return { type: 'string', format: formats[0] };
132
+ // A handful of short values repeated across many samples is an enum (`status`, `role`).
133
+ const values = [...acc.stringValues.keys()];
134
+ const looksLikeEnum = !acc.tooManyValues &&
135
+ !(key && FREE_TEXT_KEY.test(key)) &&
136
+ acc.strings >= 4 &&
137
+ values.length <= Math.min(8, acc.strings / 2) &&
138
+ values.every((v) => v.length > 0 && v.length <= 24 && !/^\d+$/.test(v) && !/\s{2,}/.test(v));
139
+ if (looksLikeEnum)
140
+ return { type: 'string', enum: values.sort() };
141
+ return { type: 'string' };
142
+ }
143
+ const DATE_TIME = /^\d{4}-\d{2}-\d{2}[Tt ]\d{2}:\d{2}:\d{2}(\.\d+)?([Zz]|[+-]\d{2}:\d{2})$/;
144
+ const DATE = /^\d{4}-\d{2}-\d{2}$/;
145
+ const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
146
+ const EMAIL = /^[^@\s]+@[^@\s]+\.[^@\s]+$/;
147
+ const URI = /^https?:\/\/[^\s]+$/;
148
+ function detectFormat(s) {
149
+ if (DATE_TIME.test(s) && isRealDate(s.slice(0, 10)))
150
+ return /^.{10}[Tt]/.test(s) ? 'date-time' : '';
151
+ if (DATE.test(s) && isRealDate(s))
152
+ return 'date';
153
+ if (UUID.test(s))
154
+ return 'uuid';
155
+ if (EMAIL.test(s))
156
+ return 'email';
157
+ if (URI.test(s) && URL.canParse(s))
158
+ return 'uri';
159
+ return '';
160
+ }
161
+ /** `2024-02-30` matches the regex but isn't a date; validators reject it, so we must too. */
162
+ function isRealDate(s) {
163
+ const d = new Date(`${s}T00:00:00Z`);
164
+ return !Number.isNaN(d.getTime()) && d.toISOString().startsWith(s);
165
+ }
166
+ //# sourceMappingURL=infer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"infer.js","sourceRoot":"","sources":["../src/infer.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Schema } from './model.js';\n\n// Schema inference works in two passes: `observe` folds every sample value into an\n// accumulator of statistics, then `finalize` turns those statistics into a schema.\n// Seeing all samples first is what lets us tell \"optional\" from \"always present\",\n// \"nullable\" from \"never null\", and an enum from free text.\n\nconst MAX_TRACKED_VALUES = 50;\n\n/** Keys whose values are free text even when the samples happen to repeat. */\nconst FREE_TEXT_KEY = /(name|title|description|summary|label|text|message|comment|bio|note|notes|body|content)$/i;\n\ninterface Acc {\n /** Times this position was observed, including nulls. */\n seen: number;\n nulls: number;\n booleans: number;\n integers: number;\n floats: number;\n negative: boolean;\n strings: number;\n stringValues: Map<string, number>;\n tooManyValues: boolean;\n /** Detected format per string ('' when none), with counts. */\n formats: Map<string, number>;\n arrays: number;\n items?: Acc;\n objects: number;\n props: Map<string, Acc>;\n}\n\nfunction emptyAcc(): Acc {\n return {\n seen: 0,\n nulls: 0,\n booleans: 0,\n integers: 0,\n floats: 0,\n negative: false,\n strings: 0,\n stringValues: new Map(),\n tooManyValues: false,\n formats: new Map(),\n arrays: 0,\n objects: 0,\n props: new Map(),\n };\n}\n\n/** Collects samples for one schema position. Call `add` per sample, then `schema()`. */\nexport class SchemaInferrer {\n private acc = emptyAcc();\n\n add(value: unknown): this {\n observe(this.acc, value);\n return this;\n }\n\n get samples(): number {\n return this.acc.seen;\n }\n\n schema(): Schema {\n return finalize(this.acc);\n }\n}\n\n/** Infer a JSON Schema (OpenAPI 3.1 dialect) that every one of `samples` validates against. */\nexport function inferSchema(...samples: unknown[]): Schema {\n const inferrer = new SchemaInferrer();\n for (const s of samples) inferrer.add(s);\n return inferrer.schema();\n}\n\nfunction observe(acc: Acc, value: unknown): void {\n acc.seen++;\n if (value === null || value === undefined) {\n acc.nulls++;\n } else if (typeof value === 'boolean') {\n acc.booleans++;\n } else if (typeof value === 'number') {\n if (Number.isInteger(value)) acc.integers++;\n else acc.floats++;\n if (value < 0) acc.negative = true;\n } else if (typeof value === 'string') {\n acc.strings++;\n const format = detectFormat(value);\n acc.formats.set(format, (acc.formats.get(format) ?? 0) + 1);\n if (!acc.tooManyValues) {\n acc.stringValues.set(value, (acc.stringValues.get(value) ?? 0) + 1);\n if (acc.stringValues.size > MAX_TRACKED_VALUES) {\n acc.tooManyValues = true;\n acc.stringValues.clear();\n }\n }\n } else if (Array.isArray(value)) {\n acc.arrays++;\n acc.items ??= emptyAcc();\n for (const item of value) observe(acc.items, item);\n } else if (typeof value === 'object') {\n acc.objects++;\n for (const [key, v] of Object.entries(value)) {\n let prop = acc.props.get(key);\n if (!prop) acc.props.set(key, (prop = emptyAcc()));\n observe(prop, v);\n }\n }\n}\n\nfunction finalize(acc: Acc, key?: string): Schema {\n const variants: Schema[] = [];\n if (acc.objects) variants.push(objectSchema(acc));\n if (acc.arrays) variants.push({ type: 'array', items: acc.items && acc.items.seen ? finalize(acc.items) : {} });\n if (acc.strings) variants.push(stringSchema(acc, key));\n if (acc.integers || acc.floats) {\n variants.push({ type: acc.floats ? 'number' : 'integer', ...(acc.negative ? {} : { minimum: 0 }) });\n }\n if (acc.booleans) variants.push({ type: 'boolean' });\n\n if (variants.length === 0) return acc.nulls ? { type: 'null' } : {};\n if (variants.length === 1) {\n const only = variants[0]!;\n if (acc.nulls) {\n only.type = [only.type, 'null'];\n if (only.enum) only.enum = [...only.enum, null];\n }\n return only;\n }\n if (acc.nulls) variants.push({ type: 'null' });\n return { anyOf: variants };\n}\n\nfunction objectSchema(acc: Acc): Schema {\n const properties: Record<string, Schema> = {};\n const required: string[] = [];\n for (const [key, prop] of acc.props) {\n properties[key] = finalize(prop, key);\n if (prop.seen === acc.objects) required.push(key);\n }\n return { type: 'object', properties, ...(required.length ? { required } : {}) };\n}\n\nfunction stringSchema(acc: Acc, key?: string): Schema {\n const formats = [...acc.formats.keys()];\n if (formats.length === 1 && formats[0]) return { type: 'string', format: formats[0] };\n\n // A handful of short values repeated across many samples is an enum (`status`, `role`).\n const values = [...acc.stringValues.keys()];\n const looksLikeEnum =\n !acc.tooManyValues &&\n !(key && FREE_TEXT_KEY.test(key)) &&\n acc.strings >= 4 &&\n values.length <= Math.min(8, acc.strings / 2) &&\n values.every((v) => v.length > 0 && v.length <= 24 && !/^\\d+$/.test(v) && !/\\s{2,}/.test(v));\n if (looksLikeEnum) return { type: 'string', enum: values.sort() };\n return { type: 'string' };\n}\n\nconst DATE_TIME = /^\\d{4}-\\d{2}-\\d{2}[Tt ]\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?([Zz]|[+-]\\d{2}:\\d{2})$/;\nconst DATE = /^\\d{4}-\\d{2}-\\d{2}$/;\nconst UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\nconst EMAIL = /^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$/;\nconst URI = /^https?:\\/\\/[^\\s]+$/;\n\nfunction detectFormat(s: string): string {\n if (DATE_TIME.test(s) && isRealDate(s.slice(0, 10))) return /^.{10}[Tt]/.test(s) ? 'date-time' : '';\n if (DATE.test(s) && isRealDate(s)) return 'date';\n if (UUID.test(s)) return 'uuid';\n if (EMAIL.test(s)) return 'email';\n if (URI.test(s) && URL.canParse(s)) return 'uri';\n return '';\n}\n\n/** `2024-02-30` matches the regex but isn't a date; validators reject it, so we must too. */\nfunction isRealDate(s: string): boolean {\n const d = new Date(`${s}T00:00:00Z`);\n return !Number.isNaN(d.getTime()) && d.toISOString().startsWith(s);\n}\n"]}
package/dist/load.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ import type { MockModel } from './model.js';
2
+ /** Load either input: an OpenAPI file, or a folder of sample responses. */
3
+ export declare function loadSource(source: string): Promise<MockModel>;
package/dist/load.js ADDED
@@ -0,0 +1,15 @@
1
+ import fs from 'node:fs/promises';
2
+ import { loadOpenApi, SpecLoadError } from './openapi.js';
3
+ import { loadSamples } from './samples.js';
4
+ /** Load either input: an OpenAPI file, or a folder of sample responses. */
5
+ export async function loadSource(source) {
6
+ let stat;
7
+ try {
8
+ stat = await fs.stat(source);
9
+ }
10
+ catch {
11
+ throw new SpecLoadError('no such file or folder', source);
12
+ }
13
+ return stat.isDirectory() ? loadSamples(source) : loadOpenApi(source);
14
+ }
15
+ //# sourceMappingURL=load.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load.js","sourceRoot":"","sources":["../src/load.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAElC,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,2EAA2E;AAC3E,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,MAAc;IAC7C,IAAI,IAAI,CAAC;IACT,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,aAAa,CAAC,wBAAwB,EAAE,MAAM,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;AACxE,CAAC","sourcesContent":["import fs from 'node:fs/promises';\nimport type { MockModel } from './model.js';\nimport { loadOpenApi, SpecLoadError } from './openapi.js';\nimport { loadSamples } from './samples.js';\n\n/** Load either input: an OpenAPI file, or a folder of sample responses. */\nexport async function loadSource(source: string): Promise<MockModel> {\n let stat;\n try {\n stat = await fs.stat(source);\n } catch {\n throw new SpecLoadError('no such file or folder', source);\n }\n return stat.isDirectory() ? loadSamples(source) : loadOpenApi(source);\n}\n"]}
@@ -0,0 +1,34 @@
1
+ /** An OpenAPI / JSON Schema schema object, already dereferenced. May contain cycles. */
2
+ export type Schema = Record<string, any>;
3
+ export interface MockResponse {
4
+ status: number;
5
+ /** True when this came from the spec's `default` response rather than an explicit code. */
6
+ isDefault?: boolean;
7
+ schema?: Schema;
8
+ /** A concrete example from the spec; preferred over generated data. */
9
+ example?: unknown;
10
+ hasExample: boolean;
11
+ contentType?: string;
12
+ }
13
+ export interface MockRoute {
14
+ method: string;
15
+ /** Path template as written in the spec, e.g. `/users/{id}`. */
16
+ path: string;
17
+ pattern: RegExp;
18
+ paramNames: string[];
19
+ operationId?: string;
20
+ responses: MockResponse[];
21
+ }
22
+ export interface MockModel {
23
+ /** OpenAPI version the schemas are written in (`3.0.x` or `3.1.x`); sample folders infer 3.1. */
24
+ openapi: string;
25
+ title: string;
26
+ version: string;
27
+ /** Path prefix from `servers[0].url`, e.g. `/v1`; requests may include or omit it. */
28
+ basePath: string;
29
+ routes: MockRoute[];
30
+ /** Non-fatal problems found while loading (lenient mode). */
31
+ warnings: string[];
32
+ /** Files the model was built from, for hot reload. */
33
+ sources: string[];
34
+ }
package/dist/model.js ADDED
@@ -0,0 +1,4 @@
1
+ // The normalized model every input (OpenAPI spec, sample folder) is converted into.
2
+ // The generator and server only ever see this, never the original source.
3
+ export {};
4
+ //# sourceMappingURL=model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model.js","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAAA,oFAAoF;AACpF,0EAA0E","sourcesContent":["// The normalized model every input (OpenAPI spec, sample folder) is converted into.\n// The generator and server only ever see this, never the original source.\n\n/** An OpenAPI / JSON Schema schema object, already dereferenced. May contain cycles. */\nexport type Schema = Record<string, any>;\n\nexport interface MockResponse {\n status: number;\n /** True when this came from the spec's `default` response rather than an explicit code. */\n isDefault?: boolean;\n schema?: Schema;\n /** A concrete example from the spec; preferred over generated data. */\n example?: unknown;\n hasExample: boolean;\n contentType?: string;\n}\n\nexport interface MockRoute {\n method: string;\n /** Path template as written in the spec, e.g. `/users/{id}`. */\n path: string;\n pattern: RegExp;\n paramNames: string[];\n operationId?: string;\n responses: MockResponse[];\n}\n\nexport interface MockModel {\n /** OpenAPI version the schemas are written in (`3.0.x` or `3.1.x`); sample folders infer 3.1. */\n openapi: string;\n title: string;\n version: string;\n /** Path prefix from `servers[0].url`, e.g. `/v1`; requests may include or omit it. */\n basePath: string;\n routes: MockRoute[];\n /** Non-fatal problems found while loading (lenient mode). */\n warnings: string[];\n /** Files the model was built from, for hot reload. */\n sources: string[];\n}\n"]}