Repository: honojs/hono
File: src/validator/validator.ts (TypeScript)

Code before:

export class VArray<T extends Schema> extends VObjectBase<T> {
  type: 'array' = 'array'
  constructor(container: T, key: string) {
    super(container, key)
  }
}

export class Validator {
  isArray: boolean = false
  query = (key: string): VString => new VString({ target: 'query', key: key })
  queries = (key: string): VStringArray => new VStringArray({ target: 'queries', key: key })
  header = (key: string): VString => new VString({ target: 'header', key: key })
  body = (key: string): VString => new VString({ target: 'body', key: key })
  json = (key: string) => {
    if (this.isArray) {
      return new VStringArray({ target: 'json', key: key })
    } else {
      return new VString({ target: 'json', key: key })
    }
  }
  array = <T extends Schema>(path: string, validator: (v: Validator) => T): VArray<T> => {
    this.isArray = true
    const res = validator(this)
    const arr = new VArray(res, path)
    this.isArray = false
    return arr
  }
  object = <T extends Schema>(path: string, validator: (v: Validator) => T): VObject<T> => {
    const res = validator(this)
    const obj = new VObject(res, path)
    return obj
  }
}

type VOptions = {
  target: Target
  key: string
  type?: 'string' | 'number' | 'boolean' | 'object'
  isArray?: boolean
}

export abstract class VBase {
  type: 'string' | 'number' | 'boolean' | 'object'
  target: Target
  baseKeys: string[] = []
  key: string
  rules: Rule[]
  sanitizers: Sanitizer[]
  isArray: boolean
  private _optional: boolean

Review comment (suggestion):
I reconsidered and think it would be better to create a new instance of `Validator`.

```ts
  array = <T extends Schema>(path: string, validator: (v: Validator) => T): VArray<T> => {
    const newValidator = new Validator()
    newValidator.isArray = true
    const res = validator(newValidator)
    const arr = new VArray(res, path)
    return arr
  }
  object = <T extends Schema>(path: string, validator: (v: Validator) => T): VObject<T> => {
    const newValidator = new Validator()
    newValidator.isArray = this.isArray
    const res = validator(newValidator)
    const obj = new VObject(res, path)
    return obj
  }
```

In this case, a different object from `this` should be invoked in `validator`.


Code after:

export class VArray<T extends Schema> extends VObjectBase<T> {
  type: 'array' = 'array'
  constructor(container: T, key: string) {
    super(container, key)
  }
}

export class Validator {
  constructor(private inArray: boolean = false) {}

  query = (key: string): VString => new VString({ target: 'query', key: key })
  queries = (key: string): VStringArray => new VStringArray({ target: 'queries', key: key })
  header = (key: string): VString => new VString({ target: 'header', key: key })
  body = (key: string): VString => new VString({ target: 'body', key: key })
  json = (key: string) => {
    if (this.inArray) {
      return new VStringArray({ target: 'json', key: key })
    } else {
      return new VString({ target: 'json', key: key })
    }
  }
  array = <T extends Schema>(path: string, validatorFn: (v: Validator) => T): VArray<T> => {
    const validator = new Validator(true)
    const res = validatorFn(validator)
    const arr = new VArray(res, path)
    return arr
  }
  object = <T extends Schema>(path: string, validatorFn: (v: Validator) => T): VObject<T> => {
    const validator = new Validator(this.inArray)
    const res = validatorFn(validator)
    const obj = new VObject(res, path)
    return obj
  }
}

type VOptions = {
  target: Target
  key: string
  type?: 'string' | 'number' | 'boolean' | 'object'
  isArray?: boolean
}

export abstract class VBase {
  type: 'string' | 'number' | 'boolean' | 'object'
  target: Target
  baseKeys: string[] = []
  key: string
  rules: Rule[]
  sanitizers: Sanitizer[]
  isArray: boolean