1f94354caSBartłomiej Bukowskiimport React from 'react';
2f94354caSBartłomiej Bukowski
3f94354caSBartłomiej Bukowskiimport { EnumParameter, FunctionArgument, FunctionParameter, ObjectParameter } from './index.types';
4f94354caSBartłomiej Bukowskiimport { isCurrentPlatformSupported } from './utils';
5*8a424bebSJames Ideimport MonoText from '../MonoText';
6f94354caSBartłomiej Bukowski
70111d1deSBartłomiej Bukowskiexport default function FunctionSignature(props: {
80111d1deSBartłomiej Bukowski  namespace: string;
90111d1deSBartłomiej Bukowski  name: string;
100111d1deSBartłomiej Bukowski  parameters: FunctionParameter[];
110111d1deSBartłomiej Bukowski  args: FunctionArgument[];
120111d1deSBartłomiej Bukowski}) {
130111d1deSBartłomiej Bukowski  return <MonoText>{generateFunctionSignature(props)}</MonoText>;
140111d1deSBartłomiej Bukowski}
150111d1deSBartłomiej Bukowski
160111d1deSBartłomiej Bukowskiexport function generateFunctionSignature({
17f94354caSBartłomiej Bukowski  namespace,
18f94354caSBartłomiej Bukowski  name,
19f94354caSBartłomiej Bukowski  parameters,
20f94354caSBartłomiej Bukowski  args,
21f94354caSBartłomiej Bukowski}: {
22f94354caSBartłomiej Bukowski  namespace: string;
23f94354caSBartłomiej Bukowski  name: string;
24f94354caSBartłomiej Bukowski  parameters: FunctionParameter[];
25f94354caSBartłomiej Bukowski  args: FunctionArgument[];
26f94354caSBartłomiej Bukowski}) {
270111d1deSBartłomiej Bukowski  return `${namespace}.${name}(${argumentsToString(args, parameters)})`;
280111d1deSBartłomiej Bukowski}
290111d1deSBartłomiej Bukowski
300111d1deSBartłomiej Bukowskifunction argumentsToString(args: FunctionArgument[], parameters: FunctionParameter[]) {
31f94354caSBartłomiej Bukowski  return parameters
32f94354caSBartłomiej Bukowski    .map((parameter, idx) => {
33f94354caSBartłomiej Bukowski      if (!isCurrentPlatformSupported(parameter.platforms)) {
34f94354caSBartłomiej Bukowski        return;
35f94354caSBartłomiej Bukowski      }
36f94354caSBartłomiej Bukowski      switch (parameter.type) {
37f94354caSBartłomiej Bukowski        case 'object':
38f94354caSBartłomiej Bukowski          return convertObjectArgumentToString(args[idx], parameter);
39f94354caSBartłomiej Bukowski        case 'enum':
40f94354caSBartłomiej Bukowski          return convertEnumArgumentToString(args[idx], parameter);
41f94354caSBartłomiej Bukowski        case 'constant':
42f94354caSBartłomiej Bukowski          return parameter.name;
43f94354caSBartłomiej Bukowski        default:
44f94354caSBartłomiej Bukowski          return String(args[idx]);
45f94354caSBartłomiej Bukowski      }
46f94354caSBartłomiej Bukowski    })
47f94354caSBartłomiej Bukowski    .filter((arg) => !!arg) // filter out all void values
48f94354caSBartłomiej Bukowski    .join(', ');
49f94354caSBartłomiej Bukowski}
50f94354caSBartłomiej Bukowski
51f94354caSBartłomiej Bukowskifunction convertObjectArgumentToString(arg: FunctionArgument, parameter: ObjectParameter) {
52f94354caSBartłomiej Bukowski  const properties = parameter.properties
53f94354caSBartłomiej Bukowski    .map((property) => {
54f94354caSBartłomiej Bukowski      // skip object properties unsupported on the current platform
55f94354caSBartłomiej Bukowski      if (!isCurrentPlatformSupported(property.platforms)) {
56f94354caSBartłomiej Bukowski        return;
57f94354caSBartłomiej Bukowski      }
58f94354caSBartłomiej Bukowski
59f94354caSBartłomiej Bukowski      if (typeof arg !== 'object' || Array.isArray(arg) /** filter out tuples/arrays */) {
60f94354caSBartłomiej Bukowski        throw new Error(
61f94354caSBartłomiej Bukowski          `Value ${arg} is not an object. Expecting object for ${parameter.name} argument`
62f94354caSBartłomiej Bukowski        );
63f94354caSBartłomiej Bukowski      }
64f94354caSBartłomiej Bukowski
65f94354caSBartłomiej Bukowski      if (!(property.name in arg)) {
66f94354caSBartłomiej Bukowski        throw new Error(
67f94354caSBartłomiej Bukowski          `Property ${
68f94354caSBartłomiej Bukowski            property.name
69f94354caSBartłomiej Bukowski          } is missing in argument. Available parameter properties: ${parameter.properties
70f94354caSBartłomiej Bukowski            .map((p) => p.name)
71f94354caSBartłomiej Bukowski            .join(', ')} and argument properties: ${Object.keys(arg).join(', ')}`
72f94354caSBartłomiej Bukowski        );
73f94354caSBartłomiej Bukowski      }
74f94354caSBartłomiej Bukowski
75f94354caSBartłomiej Bukowski      const value = arg[property.name];
76f94354caSBartłomiej Bukowski
77f94354caSBartłomiej Bukowski      // skip `undefined` values
78f94354caSBartłomiej Bukowski      if (value === undefined) {
79f94354caSBartłomiej Bukowski        return;
80f94354caSBartłomiej Bukowski      }
81f94354caSBartłomiej Bukowski
82f94354caSBartłomiej Bukowski      if (property.type === 'enum') {
838974afb9Saleqsio        const stringArgument = convertEnumArgumentToString(value, property);
848974afb9Saleqsio        if (!stringArgument) return;
858974afb9Saleqsio        return `${property.name}: ${stringArgument}`;
86f94354caSBartłomiej Bukowski      }
87f94354caSBartłomiej Bukowski
88f94354caSBartłomiej Bukowski      return `${property.name}: ${property.type === 'string' ? `"${value}"` : value}`;
89f94354caSBartłomiej Bukowski    })
90f94354caSBartłomiej Bukowski    .filter((entry) => !!entry) // filter out all void values
91f94354caSBartłomiej Bukowski    .join(',\n  ');
92f94354caSBartłomiej Bukowski
93f94354caSBartłomiej Bukowski  return `{\n  ${properties}\n}`;
94f94354caSBartłomiej Bukowski}
95f94354caSBartłomiej Bukowski
96f94354caSBartłomiej Bukowskifunction convertEnumArgumentToString(arg: FunctionArgument, { name, values }: EnumParameter) {
97f94354caSBartłomiej Bukowski  // this should always find the current value for the enum, if failed something is messed up somewhere else
98f94354caSBartłomiej Bukowski  // eslint-disable-next-line no-case-declarations
990111d1deSBartłomiej Bukowski  const value = values.find(({ value }) =>
1000111d1deSBartłomiej Bukowski    typeof value === 'object' && typeof arg === 'object'
1010111d1deSBartłomiej Bukowski      ? JSON.stringify(value) === JSON.stringify(arg) // for tuple case
1020111d1deSBartłomiej Bukowski      : value === arg
1030111d1deSBartłomiej Bukowski  );
104f94354caSBartłomiej Bukowski  if (!value) {
1058974afb9Saleqsio    return;
106f94354caSBartłomiej Bukowski  }
107f94354caSBartłomiej Bukowski  return value.name;
108f94354caSBartłomiej Bukowski}
109