All files / if-run/builtins/sci index.ts

100% Statements 26/26
100% Branches 9/9
100% Functions 5/5
100% Lines 26/26

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 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 1125x   5x     5x   5x   5x   5x   5x             5x   5x                                                                 9x 1x     8x       8x       8x     9x   9x 2x     7x                 7x     6x 7x       7x 1x   1x         6x   6x                
import {z} from 'zod';
 
import {PluginFactory} from '@grnsft/if-core/interfaces';
import {ConfigParams, PluginParams} from '@grnsft/if-core/types';
 
import {validate} from '../../../common/util/validations';
 
import {ERRORS} from '@grnsft/if-core/utils';
 
import {allDefined} from '../../../common/util/validations';
 
import {STRINGS} from '../../config';
 
const {MissingInputDataError, ConfigError} = ERRORS;
const {
  MISSING_FUNCTIONAL_UNIT_CONFIG,
  MISSING_FUNCTIONAL_UNIT_INPUT,
  SCI_MISSING_FN_UNIT,
  ZERO_DIVISION,
  MISSING_CONFIG,
} = STRINGS;
 
export const Sci = PluginFactory({
  metadata: {
    inputs: {
      carbon: {
        description: 'an amount of carbon emitted into the atmosphere',
        unit: 'gCO2e',
        'aggregation-method': {
          time: 'sum',
          component: 'sum',
        },
      },
      'functional-unit': {
        description:
          'the name of the functional unit in which the final SCI value should be expressed, e.g. requests, users',
        unit: 'none',
        'aggregation-method': {
          time: 'sum',
          component: 'sum',
        },
      },
    },
    outputs: {
      sci: {
        description: 'carbon expressed in terms of the given functional unit',
        unit: 'gCO2e',
        'aggregation-method': {
          time: 'avg',
          component: 'sum',
        },
      },
    },
  },
  configValidation: (config: ConfigParams) => {
    if (!config || !Object.keys(config)?.length) {
      throw new ConfigError(MISSING_CONFIG);
    }
 
    const schema = z
      .object({
        'functional-unit': z.string(),
      })
      .refine(data => data['functional-unit'], {
        message: MISSING_FUNCTIONAL_UNIT_CONFIG,
      });
 
    return validate<z.infer<typeof schema>>(schema, config);
  },
  inputValidation: (input: PluginParams, config: ConfigParams) => {
    const functionalUnit = config['functional-unit'];
 
    if (!(functionalUnit in input && input[functionalUnit] >= 0)) {
      throw new MissingInputDataError(MISSING_FUNCTIONAL_UNIT_INPUT);
    }
 
    const schema = z
      .object({
        carbon: z.number().gte(0),
        duration: z.number().gte(1),
      })
      .refine(allDefined, {
        message: SCI_MISSING_FN_UNIT(config['functional-unit']),
      });
 
    return validate<z.infer<typeof schema>>(schema, input);
  },
  implementation: async (inputs: PluginParams[], config: ConfigParams) => {
    return inputs.map((input, index) => {
      const functionalUnit = isNaN(config['functional-unit'])
        ? input[config['functional-unit']]
        : config['functional-unit'];
 
      if (functionalUnit === 0) {
        console.warn(ZERO_DIVISION(Sci.name, index));
 
        return {
          ...input,
          sci: input['carbon'],
        };
      }
      const calculatedResult = input['carbon'] / functionalUnit;
 
      return {
        ...input,
        sci: calculatedResult,
      };
    });
  },
  allowArithmeticExpressions: ['functional-unit'],
});