aboutsummaryrefslogtreecommitdiff
path: root/src/util.ts
blob: b7d4efea24a84244e64af65bf89876ce9e92efa3 (plain) (blame)
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
77
78
import { SyntaxKind, Type } from 'ts-morph'
import { Ctx } from './types'

export const match = <K extends string, R>(
  k: K | undefined,
  pattern: { [key in K | '_']: () => R }
) => (k && pattern[k] ? pattern[k]() : pattern._())

export const evalList = async (ctx: Ctx, effectTyps: Type[]) => {
  const effectResults: (string | undefined)[] = []
  for (const item of effectTyps ?? []) {
    const [resultKey] = await ctx.evaluateType(ctx, item)
    effectResults.push(resultKey ? resultKey : undefined)
  }
  return effectResults
}

export const applyFunc = (
  ctx: Ctx,
  fn: Type | undefined,
  val: string
): Type => {
  const resultType = (() => {
    const baseTypes = fn
      ?.getBaseTypes()
      .flatMap((t) => t.getSymbol()?.getName() ?? [])

    if (!!fn?.getProperty('return') || baseTypes?.includes('Kind1')) {
      const [key, resultNode] = ctx.createResult(
        `(${ctx.typeToString(fn)} & { input: ${val} })['return']`
      )
      ctx.removeResult(key)

      return resultNode
        ?.getType()
        .getProperty('output')
        ?.getTypeAtLocation(resultNode)
    } else {
      const [key, resultNode] = ctx.createResult(
        `ReturnType<${ctx.typeToString(fn)}>`
      )
      ctx.removeResult(key)

      const resValueNode = resultNode
        ?.asKind(SyntaxKind.PropertySignature)
        ?.getChildAtIndexIfKind(2, SyntaxKind.TypeLiteral)
        ?.getProperty('output')
        ?.getChildAtIndexIfKind(2, SyntaxKind.TypeReference)

      const functionNode = resValueNode
        ?.getChildAtIndexIfKind(1, SyntaxKind.SyntaxList)
        ?.getFirstChildIfKind(SyntaxKind.FunctionType)

      if (functionNode) {
        const typeParameters = functionNode.getTypeParameters() ?? []

        if (typeParameters.length > 0) {
          const constraint = typeParameters[0]?.getConstraint()
          if (constraint) {
            constraint?.replaceWithText(val)
          } else {
            typeParameters[0]?.setConstraint(val)
          }
        }

        return resValueNode?.getType()
      }
    }

    return undefined
  })()

  if (!resultType) {
    throw new Error('Couldnt get result for function application')
  }

  return resultType
}