messages.ts•2.28 kB
import { formatTable, mapObjectValues } from '@prisma/internals'
import { bold, dim, green, white } from 'kleur/colors'
import { id, Mapped, NoInfer } from './prelude'
interface Resource {
  __typename: string
  id: string
  displayName: string
  createdAt?: string
}
type Renderer<T> = (value: T) => string | null
type ObjectValueRenderersInput<$Object> = {
  [Key in keyof $Object]?: Renderer<$Object[Key]> | true
}
const table = <$Object extends object>(
  object: Mapped<$Object>,
  renderersInput: {
    key?: Renderer<string>
    values?: ObjectValueRenderersInput<NoInfer<$Object>>
  },
) => {
  const renderers = {
    key: renderersInput.key ?? dim,
    // eslint-disable-next-line
    values: mapObjectValues(renderersInput.values ?? ({} as any), (_: true | Renderer<any>) => (_ === true ? id : _)),
  }
  return formatTable(
    Object.entries(renderers.values)
      .map(([propertyName, renderer]) => {
        const valueRendered = renderer(object[propertyName]) as null | string // todo ask for TS help here
        if (valueRendered === null) return null
        return [renderers.key(String(propertyName)), valueRendered]
      })
      .filter(Boolean) as string[][],
  )
}
export const successMessage = (message: string) => `${green('Success!')} ${message}`
export const messages = {
  resourceCreated: (resource: Resource) =>
    successMessage(`${resource.__typename} ${resource.displayName} - ${resource.id} created.`),
  resourceDeleted: (resource: Resource) =>
    successMessage(`${resource.__typename} ${resource.displayName} - ${resource.id} deleted.`),
  resource: <$Resource extends Resource>(resource: $Resource, renderers?: ObjectValueRenderersInput<$Resource>) => {
    return messages.table(resource, {
      values: {
        displayName: (_) => white(bold(_)),
        id: true,
        createdAt: (_) => (_ ? Intl.DateTimeFormat().format(new Date(_)) : null),
        ...renderers,
      },
    })
  },
  resourceList: (records: Resource[]) => {
    if (records.length === 0) return messages.info('No records found.')
    return records.map((record) => messages.resource(record)).join('\n\n\n')
  },
  info: (message: string) => message,
  sections: (sections: string[]) => sections.join('\n\n'),
  table,
  success: successMessage,
}