1import React from 'react';
2
3import MonoText from '../MonoText';
4import { EnumParameter, FunctionArgument, FunctionParameter, ObjectParameter } from './index.types';
5import { isCurrentPlatformSupported } from './utils';
6
7export default function FunctionSignature({
8  namespace,
9  name,
10  parameters,
11  args,
12}: {
13  namespace: string;
14  name: string;
15  parameters: FunctionParameter[];
16  args: FunctionArgument[];
17}) {
18  const renderArguments = () => {
19    return parameters
20      .map((parameter, idx) => {
21        if (!isCurrentPlatformSupported(parameter.platforms)) {
22          return;
23        }
24        switch (parameter.type) {
25          case 'object':
26            return convertObjectArgumentToString(args[idx], parameter);
27          case 'enum':
28            return convertEnumArgumentToString(args[idx], parameter);
29          case 'constant':
30            return parameter.name;
31          default:
32            return String(args[idx]);
33        }
34      })
35      .filter((arg) => !!arg) // filter out all void values
36      .join(', ');
37  };
38
39  return (
40    <MonoText>
41      {namespace}.{name}({renderArguments()})
42    </MonoText>
43  );
44}
45
46function convertObjectArgumentToString(arg: FunctionArgument, parameter: ObjectParameter) {
47  const properties = parameter.properties
48    .map((property) => {
49      // skip object properties unsupported on the current platform
50      if (!isCurrentPlatformSupported(property.platforms)) {
51        return;
52      }
53
54      if (typeof arg !== 'object' || Array.isArray(arg) /** filter out tuples/arrays */) {
55        throw new Error(
56          `Value ${arg} is not an object. Expecting object for ${parameter.name} argument`
57        );
58      }
59
60      if (!(property.name in arg)) {
61        throw new Error(
62          `Property ${
63            property.name
64          } is missing in argument. Available parameter properties: ${parameter.properties
65            .map((p) => p.name)
66            .join(', ')} and argument properties: ${Object.keys(arg).join(', ')}`
67        );
68      }
69
70      const value = arg[property.name];
71
72      // skip `undefined` values
73      if (value === undefined) {
74        return;
75      }
76
77      if (property.type === 'enum') {
78        return `${property.name}: ${convertEnumArgumentToString(value, property)}`;
79      }
80
81      return `${property.name}: ${property.type === 'string' ? `"${value}"` : value}`;
82    })
83    .filter((entry) => !!entry) // filter out all void values
84    .join(',\n  ');
85
86  return `{\n  ${properties}\n}`;
87}
88
89function convertEnumArgumentToString(arg: FunctionArgument, { name, values }: EnumParameter) {
90  // this should always find the current value for the enum, if failed something is messed up somewhere else
91  // eslint-disable-next-line no-case-declarations
92  const value = values.find(({ value }) => value === arg);
93  if (!value) {
94    throw new Error(
95      `Value ${arg} not found in available values for enum parameter ${name}. Available values: ${values
96        .map((v) => `{${v.name} -> ${v.value}`)
97        .join(', ')}`
98    );
99  }
100  return value.name;
101}
102