<commit_before>import { Animationable } from 'kittik-animation-basic';
import { Canvas } from 'terminal-canvas';
import { ShapeRenderable } from 'kittik-shape-basic';
import { Slide } from './Slide';

export class SlideBuilder {
  private readonly slide: Slide = new Slide();

  public static start (): SlideBuilder {
    return new this();
  }

  public withName (name: string): this {
    this.slide.name = name;
    return this;
  }

  public withCanvas (canvas: Readonly<Canvas>): this {
    this.slide.canvas = canvas;
    return this;
  }

  public withShape (name: string, shape: ShapeRenderable): this {
    this.slide.addShape(name, shape);
    return this;
  }

  public withAnimation (name: string, animation: Animationable): this {
    this.slide.addAnimation(name, animation);
    return this;
  }

  public withOrder (shape: string, animations?: string[]): this {
    this.slide.addOrder(shape, animations);
    return this;
  }

  public end (): Slide {
    return this.slide;
  }
}<commit_msg>feat: 🎸 improve typecheck and autocompletion for SlideBuilder<commit_after>import { Animationable } from 'kittik-animation-basic';
import { Canvas } from 'terminal-canvas';
import { ShapeRenderable } from 'kittik-shape-basic';
import { Slide } from './Slide';

type TShapeAccumulator<TSlideBuilder, TNextShape> =
  TSlideBuilder extends SlideBuilder<infer TShapes, infer TAnimations>
    ? SlideBuilder<TShapes | TNextShape, TAnimations>
    : never;

type TAnimationAccumulator<TSlideBuilder, TNextAnimation> =
  TSlideBuilder extends SlideBuilder<infer TShapes, infer TAnimations>
    ? SlideBuilder<TShapes, TAnimations | TNextAnimation>
    : never;

export class SlideBuilder<TShape, TAnimation> {
  private readonly slide: Slide = new Slide();

  public static start (): SlideBuilder<never, never> {
    return new this();
  }

  public withName (name: string): this {
    this.slide.name = name;
    return this;
  }

  public withCanvas (canvas: Readonly<Canvas>): this {
    this.slide.canvas = canvas;
    return this;
  }

  public withShape <T extends string>(name: T, shape: ShapeRenderable): TShapeAccumulator<this, T> {
    this.slide.addShape(name, shape);

    // eslint-disable-next-line no-warning-comments
    // TODO: think about returning this and accumulator type here
    // Accumulator type in result returns SlideBuilder anyway, so seems like a bug in TypeScript?
    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
    // @ts-expect-error
    return this;
  }

  public withAnimation <T extends string>(name: T, animation: Animationable): TAnimationAccumulator<this, T> {
    this.slide.addAnimation(name, animation);

    // eslint-disable-next-line no-warning-comments
    // TODO: think about returning this and accumulator type here
    // Accumulator type in result returns SlideBuilder anyway, so seems like a bug in TypeScript?
    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
    // @ts-expect-error
    return this;
  }

  public withOrder (shape: TShape, animations?: TAnimation[]): this {
    this.slide.addOrder(String(shape), animations?.map(String));
    return this;
  }

  public end (): Slide {
    return this.slide;
  }
}
{'fraction_non_alphanumeric': 0.11163080760835672, 'fraction_numerical': 0.0, 'mean_word_length': 3.795216741405082, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6532962', 'n_tokens_mistral': 1004, 'n_tokens_neox': 968, 'n_words': 273}