UNPKG

2.29 kBPlain TextView Raw
1import { casesExhausted } from './prelude.js'
2
3type Parameter = { type: 'name'; value: string } | { type: 'destructured'; names: string[] }
4
5export const analyzeFunction = (fn: (...args: [...any[]]) => unknown) => {
6 const groups = fn.toString().match(functionPattern)?.groups
7 if (!groups) throw new Error(`Could not extract groups from function.`)
8
9 const body = groups[`bodyStatement`] ?? groups[`bodyExpression`]
10 if (body === undefined) throw new Error(`Could not extract body from function.`)
11
12 const parameters: Parameter[] = []
13
14 if (groups[`parameters`]) {
15 const results = [...groups[`parameters`].matchAll(functionParametersPattern)]
16 const resultParameters = results.map(result => {
17 const type = result.groups?.[`destructured`] ? `destructured` : result.groups?.[`name`] ? `name` : null
18
19 switch (type) {
20 case `destructured`:
21 const valueRaw = result.groups![`destructured`]!
22 const names = [...valueRaw.matchAll(destructuredPattern)].map(result => {
23 const name = result.groups![`name`]
24 if (name === undefined) throw new Error(`Could not extract name from destructured parameter.`)
25 return name
26 })
27 return {
28 type,
29 names,
30 } as const
31 case `name`:
32 return {
33 type,
34 value: result.groups![`name`]!,
35 } as const
36 case null:
37 throw new Error(`Could not determine type of parameter.`)
38 default:
39 throw casesExhausted(type)
40 }
41 })
42
43 parameters.push(...resultParameters)
44 }
45
46 return {
47 body,
48 parameters,
49 }
50}
51
52/**
53 * @see https://regex101.com/r/9kCK86/4
54 */
55// const functionPattern = /(?:[A-z])?\s*(?:\((?<parameters>.*)\))\s*(?:=>)?\s*{(?<body>.*)(?=})/s
56
57/**
58 * @see https://regex101.com/r/U0JtfS/1
59 */
60const functionPattern =
61 /^(?:(?<async>async)\s+)?(?:function\s+)?(?:(?<name>[A-z_0-9]+)\s*)?\((?<parameters>[^)]*)\)\s*(?:=>\s*(?<bodyExpression>[^\s{].*)|(?:=>\s*)?{(?<bodyStatement>.*)})$/s
62
63/**
64 * @see https://regex101.com/r/tE2dV5/2
65 */
66const functionParametersPattern = /(?<destructured>\{[^}]+\})|(?<name>[A-z_][A-z_0-9]*)/gs
67
68/**
69 * https://regex101.com/r/WHwazx/1
70 */
71const destructuredPattern = /(?<name>[A-z_][A-z_0-9]*)(?::[^},]+)?/gs
72
\No newline at end of file