lean4-code-actions
Version:
Refactorings and snippets for Lean 4
102 lines (69 loc) • 4.68 kB
text/typescript
import $assert from 'assert'
import * as process from 'process'
import { equals, identity } from 'remeda'
import { RefinementCtx, ZodIssueCode } from 'zod'
import { isTrue } from './boolean'
import { Filter, FilterTwo } from './Filter'
import { fetchBooleanEnvVar } from './process'
import { includes } from './remeda/includes'
import { nequals } from './remeda/nequals'
import { toString } from './string'
export type CheckUnary<Out, A> = (a: A, $a: string, context?: Record<string, unknown>, $message?: string) => Out
export type CheckBinary<Out, A, B> = (a: A, b: B, $a: string, $b: string, context?: Record<string, unknown>, $message?: string) => Out
export type CheckByUnary<OutBy, A> = (filter: Filter<A>, $filter?: string) => OutBy
export type CheckByBinary<OutBy, A, B> = (filter: FilterTwo<A>, $filter?: string) => OutBy
export type AssertUnary<A> = CheckUnary<void, A>
export type AssertBinary<A, B> = CheckBinary<void, A, B>
export type AssertByUnary<A> = CheckByUnary<AssertUnary<A>, A>
export type AssertByBinary<A, B> = CheckByBinary<AssertBinary<A, B>, A, B>
export type GetErrorOutput = Error | undefined
export type GetErrorUnary<A> = CheckUnary<GetErrorOutput, A>
export type GetErrorBinary<A, B> = CheckBinary<GetErrorOutput, A, B>
export type GetErrorByUnary<A> = CheckByUnary<GetErrorUnary<A>, A>
export type GetErrorByBinary<A, B> = CheckByBinary<GetErrorBinary<A, B>, A, B>
export type RefineUnary<A> = (ctx: RefinementCtx) => CheckUnary<void, A>
export type RefineBinary<A, B> = (ctx: RefinementCtx) => CheckBinary<void, A, B>
export type RefineByUnary<A> = CheckByUnary<RefineUnary<A>, A>
export type RefineByBinary<A, B> = CheckByBinary<RefineBinary<A, B>, A, B>
const withContext = fetchBooleanEnvVar('ASSERT_WITH_CONTEXT', process.env.ASSERT_WITH_CONTEXT)
export const assertOne = <A>(filter: (a: A) => boolean, $filter = filter.name): AssertUnary<A> => (a: A, $a = `${a}`, context?: Record<string, unknown>, $message?: string) => {
return $assert.strict(
filter(a),
getMessage($filter, [a], [$a], $message, context)
)
}
export const assertTwo = <A, B = A>(filter: (a: A, b: B) => boolean, $filter = filter.name): AssertBinary<A, B> => (a: A, b: B, $a = `${a}`, $b = `${b}`, context?: Record<string, unknown>, $message?: string) => {
return $assert.strict(
filter(a, b),
getMessage($filter, [a, b], [$a, $b], $message, context)
)
}
export const getErrorOne = <A>(filter: (a: A) => boolean, $filter = filter.name): GetErrorUnary<A> => (a: A, $a = `${a}`, context?: Record<string, unknown>, $message?: string) => {
return filter(a) ? undefined : new Error(getMessage($filter, [a], [$a], $message, context))
}
export const getErrorTwo = <A, B = A>(filter: (a: A, b: B) => boolean, $filter = filter.name): GetErrorBinary<A, B> => (a: A, b: B, $a = `${a}`, $b = `${b}`, context?: Record<string, unknown>, $message?: string) => {
return filter(a, b) ? undefined : new Error(getMessage($filter, [a, b], [$a, $b], $message, context))
}
export const refineOneR = <A>(filter: (a: A) => boolean, $filter = filter.name): RefineUnary<A> => (ctx: RefinementCtx) => (a: A, $a = `${a}`, context?: Record<string, unknown>, $message?: string) => {
if (!filter(a)) ctx.addIssue({ code: ZodIssueCode.custom, message: getMessage($filter, [a], [$a], $message), params: (context ?? {}) })
}
export const refineTwoR = <A, B = A>(filter: (a: A, b: B) => boolean, $filter = filter.name): RefineBinary<A, B> => (ctx: RefinementCtx) => (a: A, b: B, $a = `${a}`, $b = `${b}`, context?: Record<string, unknown>, $message?: string) => {
if (!filter(a, b)) ctx.addIssue({ code: ZodIssueCode.custom, message: getMessage($filter, [a, b], [$a, $b], $message), params: (context ?? {}) })
}
export const refineOne = (ctx: RefinementCtx) => <A>(filter: (a: A) => boolean, $filter = filter.name) => refineOneR(filter, $filter)(ctx)
export const refineTwo = (ctx: RefinementCtx) => <A, B = A>(filter: (a: A, b: B) => boolean, $filter = filter.name) => refineTwoR(filter, $filter)(ctx)
export function getMessage($func: string, args: unknown[], $args: string[], $message?: string, context?: Record<string, unknown>) {
return [
[
`${$func}(${$args.join(', ')})`,
`${$func}(${args.map(toStringForAssert).join(', ')})`,
$message,
].filter(identity).join(' ~ '),
withContext ? toString(context) : '',
].filter(identity).join('\n')
}
export const toStringForAssert = (s: unknown) => toString(s === '' ? '<empty-string>' : s)
export const assertEq = assertTwo(equals)
export const assertNeq = assertTwo(nequals)
export const assertIncludes = assertTwo(includes)
export const assertTrue = assertOne(isTrue)