All files / json-type/src/schema Walker.ts

71.73% Statements 33/46
58.33% Branches 14/24
75% Functions 3/4
78.37% Lines 29/37

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 70 71 72 73 74 75 76            36x 36x 1x 1x     1x     323x 323x                       182x 182x     22x 22x 22x 22x 22x     35x 209x 35x     32x 32x 32x 32x     5x 38x 5x     46x 46x                   1x 21x 1x              
import type {Schema} from './schema';
 
export interface WalkerOpts {
  onType?: (type: Schema) => void;
}
 
export class Walker {
  public static readonly walk = (type: Schema, opts: WalkerOpts = {}): void => {
    const walker = new Walker(opts);
    walker.walk(type);
  };
 
  constructor(private opts: WalkerOpts = {}) {}
 
  public walk(type: Schema): void {
    const onType = this.opts.onType ?? ((type: Schema) => {});
    switch (type.kind) {
      case 'key': {
        onType(type);
        this.walk(type.value as Schema);
        break;
      }
      case 'any':
      case 'con':
      case 'bool':
      case 'num':
      case 'str':
      case 'bin': {
        onType(type);
        break;
      }
      case 'arr': {
        onType(type);
        Iif (type.head) for (const t of type.head) this.walk(t);
        if (type.type) this.walk(type.type);
        Iif (type.tail) for (const t of type.tail) this.walk(t);
        break;
      }
      case 'obj': {
        onType(type);
        for (const key of type.keys) this.walk(key.value);
        break;
      }
      case 'map': {
        onType(type);
        this.walk(type.value);
        Iif (type.key) this.walk(type.key);
        break;
      }
      case 'or': {
        onType(type);
        for (const t of type.types) this.walk(t as Schema);
        break;
      }
      case 'ref': {
        onType(type);
        break;
      }
      case 'fn':
      case 'fn$': {
        onType(type);
        this.walk(type.req as Schema);
        this.walk(type.res as Schema);
        break;
      }
      case 'module': {
        onType(type);
        for (const alias of type.keys) this.walk(alias.value as Schema);
        break;
      }
      default:
        throw new Error('UNK_KIND');
    }
  }
}