All files / libs/amalia-lang/formula/evaluate/shared/src formats.ts

100% Statements 94/94
97.36% Branches 37/38
100% Functions 2/2
100% Lines 94/94

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 951x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 3x 3x 3x 3x 3x 3x 3x 3x 3x 4x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 42x 42x 2x 2x 40x 40x 42x 42x 42x 22x 22x 9x 9x 13x 42x 6x 6x 3x 3x 3x 3x 42x 6x 6x 3x 3x 3x 3x 42x 6x 3x 3x 3x 42x 42x 42x 42x  
import { match } from 'ts-pattern';
 
import { TokenType, type VariableDefinition } from '@amalia/amalia-lang/tokens/types';
import { type ComputedStatement } from '@amalia/core/types';
import { FormatsEnum } from '@amalia/data-capture/fields/types';
 
/**
 * get the format from the machine name, either from a custom object or a computed object
 *
 * @param tokenType
 * @param machineName the machine name to look for
 * @param computedStatement the computed statement to look in
 * @param customObjectMachineName The custom object definition machine name (to not look inside every custom object definition)
 *
 * @returns an object, composed by the usable format, and the fact that it is required or not
 */
export const getFormatFromMachineName = (
  tokenType: TokenType.FIELD | TokenType.PROPERTY,
  machineName: string,
  computedStatement: ComputedStatement,
  customObjectMachineName: string,
): {
  format?: FormatsEnum;
  isRequired?: boolean;
} =>
  match(tokenType)
    .with(TokenType.PROPERTY, () => {
      const customObjectDefinition = computedStatement.definitions.customObjects[customObjectMachineName];
 
      const { format: objectDefinitionFormat, isRequired } = customObjectDefinition.properties[machineName] || {};
 
      return {
        format: objectDefinitionFormat,
        isRequired,
      };
    })
    .with(TokenType.FIELD, () => {
      const computedObjectDefinition = computedStatement.definitions.variables[machineName] as
        | VariableDefinition
        | undefined;
 
      return {
        format: computedObjectDefinition?.format,
        isRequired: false,
      };
    })
    .exhaustive();
 
/**
 * Function to validate a raw value against a format
 *
 * @param value
 * @param format
 * @param required
 */
// eslint-disable-next-line sonarjs/cognitive-complexity -- It's a series of validators.
export const validateValueWithFormat = (value: unknown, format?: FormatsEnum, required: boolean = false): void => {
  // If value is required and not provided, throw an error
  if (required && (value === undefined || value === null || value === '')) {
    throw new Error('Please enter a value!');
  }
 
  switch (format) {
    case FormatsEnum.currency:
    case FormatsEnum.number:
    case FormatsEnum.percent:
      // If it's not a number, throw the error
      if (!/^-?\d+(?:\.\d+)?$/u.test(value?.toString() ?? '') && value !== '') {
        throw new Error(`Please enter a number${required ? '' : ' or remove it'}!`);
      }
      break;
    case FormatsEnum.date: {
      // If it's not a date following YYYY-MM-DD format, throw an error
      if (!/^\d{4}-\d{2}-\d{2}$/u.test(value?.toString() ?? '') && value !== '') {
        throw new Error(`Please enter a date as YYYY-MM-DD${required ? '' : ' or remove it'}!`);
      }
      break;
    }
    case FormatsEnum.boolean: {
      // If it's not a boolean, throw an error
      if (!/^(?:true|false)$/u.test(value?.toString() ?? '') && value !== '') {
        throw new Error(`Please enter a boolean (true or false)${required ? '' : ' or remove it'}!`);
      }
      break;
    }
    case FormatsEnum.text:
      if (typeof value !== 'string') {
        throw new Error(`Please enter a text value${required ? '' : ' or remove it'}!`);
      }
      break;
    default:
    // Do nothing
  }
};