All files / generator StringGenerator.ts

74.07% Statements 20/27
64% Branches 16/25
100% Functions 2/2
76.92% Lines 20/26

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69          9x       244x     244x 123x       121x 1x   1x 1x             120x               104x   1x   1x   1x   1x   12x       12x 12x 12x     12x 12x                        
import { BaseGenerator, type GeneratorOptions } from './BaseGenerator'
import type { StringOptions } from '../schema/data'
 
export default class StringGenerator extends BaseGenerator {
  constructor(opts: GeneratorOptions) {
    super(opts)
  }
 
  generate(options: Partial<StringOptions> = {}): string {
    const g = this.generator
 
    // 1) enum has highest priority
    if (options.enum && options.enum.length > 0) {
      return g.helpers.arrayElement(options.enum)
    }
 
    // 2) pattern next
    if (options.pattern) {
      try {
        // Strip leading ^ and trailing $ anchors which faker treats as literals
        const patternStr = options.pattern.replace(/^\^/, '').replace(/\$$/, '')
        return g.helpers.fromRegExp(patternStr)
      } catch {
        // fall through to other strategies if regex invalid
      }
    }
 
    // 3) format specific
    switch (options.format) {
    case 'lorem':
    // generates a sentence by default, or X sentences if specified
      return g.lorem.sentences({
        min: options.minLength ?? 1,
        max: options.maxLength ?? options.minLength ?? 3,
      })
    case 'uuid':
      return g.string.uuid()
    case 'url':
      return g.internet.url()
    case 'ipv4':
      return g.internet.ipv4()
    case 'ipv6':
      return g.internet.ipv6()
    case 'hostname':
      return g.internet.domainName()
    default:
      break
    }
 
    // 4) generic string honoring min/max length if provided
    const min = Math.max(0, options.minLength ?? 1)
    const max = Math.max(min, options.maxLength ?? Math.max(min, 16))
    const length = min === max ? min : g.number.int({ min, max })
 
    // Prefer alphanumeric stable output
    try {
      return g.string.alphanumeric({ length })
    } catch {
      // Fallback: build from characters
      const chars = g.string.alphanumeric({ length: 32 })
      let out = ''
      for (let i = 0; i < length; i++) {
        out += chars[g.number.int({ min: 0, max: chars.length - 1 })]
      }
      return out
    }
  }
}