@specbook/codegen 0.4.0 → 0.5.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@specbook/codegen",
3
- "version": "0.4.0",
3
+ "version": "0.5.1",
4
4
  "description": "Turns an OpenAPI or Swagger document into types, examples, schemas and metadata, in Node or in a browser.",
5
5
  "keywords": [
6
6
  "specbook",
@@ -40,7 +40,7 @@
40
40
  "swagger2openapi": "7.0.8"
41
41
  },
42
42
  "devDependencies": {
43
- "@specbook/core": "0.4.0",
43
+ "@specbook/core": "0.5.1",
44
44
  "@types/node": "24.19.2",
45
45
  "@types/swagger2openapi": "7.0.4",
46
46
  "typescript": "7.0.2"
package/src/build.ts CHANGED
@@ -397,17 +397,16 @@ export function generateFromDoc(
397
397
  if (defaultType) responseTypes.push(`${st}: ${defaultType}`)
398
398
  }
399
399
  }
400
- // ---- request examples: spec-defined first, then generated default and dynamic
400
+ // ---- request examples: spec-defined first, then the generated default
401
401
  const fileFieldPaths = body?.encoding === 'multipart' ? fileFields(body.schema, resolve) : []
402
402
  const wholeBodyFile = body?.encoding === 'binary'
403
403
  const sample = `./${SAMPLE_FILE}`
404
- const paramsFor = (fake: boolean) => {
404
+ const paramsFor = () => {
405
405
  const pick = (where: string) => {
406
406
  const out: Record<string, unknown> = {}
407
407
  for (const p of group(where)) {
408
408
  if (p.example !== undefined) out[p.name] = p.example
409
- else if (p.required)
410
- out[p.name] = synthesize(p.schema, resolve, 0, [], p.name, undefined, fake)
409
+ else if (p.required) out[p.name] = synthesize(p.schema, resolve, 0, [], p.name)
411
410
  }
412
411
  return Object.keys(out).length ? out : undefined
413
412
  }
@@ -433,7 +432,7 @@ export function generateFromDoc(
433
432
  title: ex.summary ?? key,
434
433
  summary: ex.description,
435
434
  source: 'spec',
436
- ...paramsFor(false),
435
+ ...paramsFor(),
437
436
  body: bodyFor(sanitizeExample(ex.value)),
438
437
  })
439
438
  }
@@ -442,30 +441,16 @@ export function generateFromDoc(
442
441
  name: take('example'),
443
442
  title: 'Example',
444
443
  source: 'spec',
445
- ...paramsFor(false),
444
+ ...paramsFor(),
446
445
  body: bodyFor(sanitizeExample(body.media.example)),
447
446
  })
448
447
  const plain = {
449
- ...paramsFor(false),
448
+ ...paramsFor(),
450
449
  body: body?.schema
451
- ? bodyFor(synthesize(body.schema, resolve, 0, [], '', undefined, false, true))
452
- : undefined,
453
- }
454
- const dynamic = {
455
- ...paramsFor(true),
456
- body: body?.schema
457
- ? bodyFor(synthesize(body.schema, resolve, 0, [], '', undefined, true, true))
450
+ ? bodyFor(synthesize(body.schema, resolve, 0, [], '', undefined, true))
458
451
  : undefined,
459
452
  }
460
453
  docs.push({ name: take('default'), title: 'Default', source: 'generated', ...plain })
461
- if (JSON.stringify(dynamic) !== JSON.stringify(plain))
462
- docs.push({
463
- name: take('dynamic'),
464
- title: 'Dynamic',
465
- summary: 'Generated values, fresh on every play.',
466
- source: 'generated',
467
- ...dynamic,
468
- })
469
454
  for (const d of docs)
470
455
  exampleFiles.push({
471
456
  path: `examples/${id}/${d.name}.example.json`,
package/src/schema.ts CHANGED
@@ -247,41 +247,6 @@ function exampleBoolean(key: string): boolean {
247
247
  )
248
248
  }
249
249
 
250
- const FAKE_BY_FORMAT: Record<string, string> = {
251
- email: 'internet.email',
252
- uuid: 'string.uuid',
253
- uri: 'internet.url',
254
- url: 'internet.url',
255
- hostname: 'internet.domainName',
256
- ipv4: 'internet.ipv4',
257
- }
258
-
259
- const FAKE_BY_NAME: [RegExp, string][] = [
260
- [/^(first_?name|given_?name)$/, 'person.firstName'],
261
- [/^(last_?name|family_?name|surname)$/, 'person.lastName'],
262
- [/^(full_?name|display_?name)$/, 'person.fullName'],
263
- [/^name$/, 'word.noun'],
264
- [/^(user_?name|login|handle)$/, 'internet.username'],
265
- [/^e?-?mail(_?address)?$/, 'internet.email'],
266
- [/^(phone|phone_?number|mobile)$/, 'phone.number'],
267
- [/^(city|town)$/, 'location.city'],
268
- [/^country$/, 'location.country'],
269
- [/^(postal_?code|zip|zip_?code)$/, 'location.zipCode'],
270
- [/^(line1|address|street|address_?line_?1)$/, 'location.streetAddress'],
271
- [/^(company|organization|org)$/, 'company.name'],
272
- [/^(title|subject)$/, 'lorem.sentence'],
273
- [/^(description|summary|bio|about|body|comment|note|notes|message)$/, 'lorem.sentence'],
274
- [/^(url|website|homepage)$/, 'internet.url'],
275
- ]
276
-
277
- /** `{{faker.*}}` placeholder for a string leaf, chosen by format first and then by field name. */
278
- export function fakerFor(key: string, format?: string): string | undefined {
279
- const path =
280
- (format && FAKE_BY_FORMAT[format]) ||
281
- FAKE_BY_NAME.find(([re]) => re.test(key.toLowerCase()))?.[1]
282
- return path ? `{{faker.${path}}}` : undefined
283
- }
284
-
285
250
  /** Deepest nesting of objects and arrays an example goes into before it settles for an empty one. */
286
251
  const MAX_DEPTH = 6
287
252
 
@@ -351,22 +316,17 @@ export function synthesize(
351
316
  seen: string[] = [],
352
317
  key = '',
353
318
  status?: number,
354
- fake = false,
355
319
  sparse = false,
356
320
  ): unknown {
357
321
  if (!schema) return null
358
322
  const again = (s: Schema | undefined, k = key, d = depth, sn = seen) =>
359
- synthesize(s, resolve, d, sn, k, status, fake, sparse)
323
+ synthesize(s, resolve, d, sn, k, status, sparse)
360
324
  if (schema.$ref) {
361
325
  const target = resolve(schema.$ref)
362
326
  // a reference back into itself carries on as "required fields only", which the depth rules then end
363
327
  if (seen.includes(schema.$ref)) return again(target, key, Math.max(depth, MAX_DEPTH), [])
364
328
  return again(target, key, depth, [...seen, schema.$ref])
365
329
  }
366
- if (fake && schema.type === 'string' && !schema.enum) {
367
- const generated = fakerFor(key, schema.format)
368
- if (generated) return generated
369
- }
370
330
  // a spec example that contradicts its own schema (a string field whose example is an array) is ignored
371
331
  if (schema.example !== undefined && fits(schema, schema.example))
372
332
  return schema.enum