type Macro = {
  test(): void
}

type Harness = {}

type ZoraxPlugin<U> = () => <T extends Harness>(harness: T) => T & U

const withMacro: ZoraxPlugin<Macro> = () => <T extends Harness>(
  harness: T
): T & Macro => ({
  ...harness,
  test() {},
})

type Spy = {
  spy(): void
}

const withSpy: ZoraxPlugin<Spy> = () => <T extends Harness>(
  harness: T
): T & Spy => ({
  ...harness,
  spy() {},
})

const o = { ok: 1 }

const om = withSpy()(withMacro()(o))

om.ok
om.test
om.spy

plug(a, b, c, d, e)
  .plug(e, g, h, i, j)
  .create()

function plug(): void

function plug(): void

function plug(...plugins) {
  return x0 => plugins.reduce((x, f) => f(x), x0)
}

const op = plug(withMacro, withSpy)(o)
