From 9dddd5dcd226ed75b2a6968df6bdc55ab8374f31 Mon Sep 17 00:00:00 2001 From: manushak Date: Thu, 19 Sep 2024 20:48:24 +0400 Subject: [PATCH] feat(builtins): refactor , and plugins --- src/if-run/builtins/coefficient/index.ts | 173 +++++--------------- src/if-run/builtins/divide/index.ts | 195 +++++++---------------- src/if-run/builtins/sci/index.ts | 189 +++++++--------------- 3 files changed, 160 insertions(+), 397 deletions(-) diff --git a/src/if-run/builtins/coefficient/index.ts b/src/if-run/builtins/coefficient/index.ts index 12de779d..167fe14e 100644 --- a/src/if-run/builtins/coefficient/index.ts +++ b/src/if-run/builtins/coefficient/index.ts @@ -1,143 +1,52 @@ -import {z, ZodType} from 'zod'; - -import { - ERRORS, - evaluateInput, - evaluateConfig, - evaluateArithmeticOutput, - getParameterFromArithmeticExpression, - validateArithmeticExpression, -} from '@grnsft/if-core/utils'; -import { - mapConfigIfNeeded, - mapOutputIfNeeded, -} from '@grnsft/if-core/utils/helpers'; -import { - CoefficientConfig, - ExecutePlugin, - MappingParams, - PluginParametersMetadata, - PluginParams, -} from '@grnsft/if-core/types'; +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 {STRINGS} from '../../config'; - -const {ConfigError} = ERRORS; -const {MISSING_CONFIG} = STRINGS; +export const Coefficient = PluginFactory({ + metadata: { + inputs: {}, + outputs: {}, + }, + configValidation: z.object({ + coefficient: z.number(), + 'input-parameter': z.string().min(1), + 'output-parameter': z.string().min(1), + }), + inputValidation: (input: PluginParams, config: ConfigParams) => { + const inputData = { + 'input-parameter': input[config['input-parameter']], + }; + const validationSchema = z.record(z.string(), z.number()); + validate(validationSchema, inputData); -export const Coefficient = ( - config: CoefficientConfig, - parametersMetadata: PluginParametersMetadata, - mapping: MappingParams -): ExecutePlugin => { - const metadata = { - kind: 'execute', - inputs: parametersMetadata?.inputs, - outputs: parametersMetadata?.outputs, - }; + return input; + }, + implementation: async (inputs: PluginParams[], config: ConfigParams = {}) => { + const inputParameter = config['input-parameter']; + const outputParameter = config['output-parameter']; + const coefficient = config['coefficient']; - /** - * Calculate the product of each input parameter. - */ - const execute = (inputs: PluginParams[]) => { - const safeConfig = validateConfig(); - const { - 'input-parameter': inputParameter, - 'output-parameter': outputParameter, - } = safeConfig; return inputs.map(input => { - const calculatedConfig = evaluateConfig({ - config: safeConfig, - input, - parametersToEvaluate: ['input-parameter', 'coefficient'], - }); - - const safeInput = validateSingleInput(input, inputParameter); - const coefficient = Number(calculatedConfig['coefficient']); - const calculatedResult = calculateProduct( - safeInput, - calculatedConfig['input-parameter'], - coefficient - ); - const result = { ...input, - ...safeInput, - ...evaluateArithmeticOutput(outputParameter, calculatedResult), + [outputParameter]: calculateProduct(input, inputParameter, coefficient), }; - return mapOutputIfNeeded(result, mapping); + return result; }); - }; - - /** - * Checks for required fields in input. - */ - const validateSingleInput = ( - input: PluginParams, - configInputParameter: string - ) => { - const inputParameter = - getParameterFromArithmeticExpression(configInputParameter); - const evaluatedInput = evaluateInput(input); - - const inputData = { - [inputParameter]: evaluatedInput[inputParameter], - }; - const validationSchema = z.record(z.string(), z.number()); - validate(validationSchema, inputData); - - return evaluatedInput; - }; - - /** - * Calculates the product of the energy components. - */ - const calculateProduct = ( - input: PluginParams, - inputParameter: string | number, - coefficient: number - ) => - (isNaN(Number(inputParameter)) ? input[inputParameter] : inputParameter) * - coefficient; - - /** - * Checks config value are valid. - */ - const validateConfig = () => { - if (!config) { - throw new ConfigError(MISSING_CONFIG); - } - - const mappedConfig = mapConfigIfNeeded(config, mapping); - - const configSchema = z - .object({ - coefficient: z.preprocess( - value => validateArithmeticExpression('coefficient', value), - z.number() - ), - 'input-parameter': z.string().min(1), - 'output-parameter': z.string().min(1), - }) - .refine(params => { - Object.entries(params).forEach(([param, value]) => - validateArithmeticExpression(param, value) - ); - - return true; - }); - - return validate>( - configSchema as ZodType, - mappedConfig - ); - }; - - return { - metadata, - execute, - }; -}; + }, + allowArithmeticExpressions: ['input-parameter', 'coefficient'], +}); + +/** + * Calculates the product of the energy components. + */ +const calculateProduct = ( + input: PluginParams, + inputParameter: string | number, + coefficient: number +) => + (isNaN(Number(inputParameter)) ? input[inputParameter] : inputParameter) * + coefficient; diff --git a/src/if-run/builtins/divide/index.ts b/src/if-run/builtins/divide/index.ts index 07ab3ba8..ff35fd9b 100644 --- a/src/if-run/builtins/divide/index.ts +++ b/src/if-run/builtins/divide/index.ts @@ -1,110 +1,27 @@ import {z} from 'zod'; -import { - ERRORS, - evaluateInput, - evaluateConfig, - evaluateArithmeticOutput, - validateArithmeticExpression, - getParameterFromArithmeticExpression, -} from '@grnsft/if-core/utils'; -import { - mapConfigIfNeeded, - mapOutputIfNeeded, -} from '@grnsft/if-core/utils/helpers'; -import { - ExecutePlugin, - PluginParams, - ConfigParams, - PluginParametersMetadata, - MappingParams, -} from '@grnsft/if-core/types'; +import {PluginFactory} from '@grnsft/if-core/interfaces'; +import {ConfigParams, PluginParams} from '@grnsft/if-core/types'; import {validate} from '../../../common/util/validations'; -import {STRINGS} from '../../config'; - -const {ConfigError, MissingInputDataError} = ERRORS; -const {MISSING_CONFIG, MISSING_INPUT_DATA, ZERO_DIVISION} = STRINGS; - -export const Divide = ( - config: ConfigParams, - parametersMetadata: PluginParametersMetadata, - mapping: MappingParams -): ExecutePlugin => { - const metadata = { - kind: 'execute', - inputs: parametersMetadata?.inputs, - outputs: parametersMetadata?.outputs, - }; - - /** - * Calculate the division of each input parameter. - */ - const execute = (inputs: PluginParams[]) => { - const safeConfig = validateConfig(); - const {numerator, denominator, output} = safeConfig; - - return inputs.map((input, index) => { - const evaluatedConfig = evaluateConfig({ - config: safeConfig, - input, - parametersToEvaluate: ['numerator', 'denominator'], - }); - const safeInput = validateSingleInput(input, safeConfig); - const calculatedResult = calculateDivide(safeInput, index, { - numerator: evaluatedConfig.numerator || numerator, - denominator: evaluatedConfig.denominator || denominator, - }); +import {ERRORS} from '@grnsft/if-core/utils'; - const result = { - ...input, - ...safeInput, - ...evaluateArithmeticOutput(output, calculatedResult), - }; - - return mapOutputIfNeeded(result, mapping); - }); - }; - - /** - * Checks config value are valid. - */ - const validateConfig = () => { - if (!config) { - throw new ConfigError(MISSING_CONFIG); - } - - const mappedConfig = mapConfigIfNeeded(config, mapping); - const schema = z - .object({ - numerator: z.string().min(1), - denominator: z.string().or(z.number()), - output: z.string(), - }) - .refine(params => { - Object.entries(params).forEach(([param, value]) => - validateArithmeticExpression(param, value) - ); - - return true; - }); - - return validate>(schema, mappedConfig); - }; +import {STRINGS} from '../../config'; - /** - * Checks for required fields in input. - */ - const validateSingleInput = ( - input: PluginParams, - safeConfig: ConfigParams - ) => { - const numerator = getParameterFromArithmeticExpression( - safeConfig.numerator - ); - const denominator = getParameterFromArithmeticExpression( - safeConfig.denominator - ); +const {MissingInputDataError} = ERRORS; +const {MISSING_INPUT_DATA, ZERO_DIVISION} = STRINGS; +export const Divide = PluginFactory({ + metadata: { + inputs: {}, + outputs: {}, + }, + configValidation: z.object({ + numerator: z.string().min(1), + denominator: z.string().or(z.number()), + output: z.string(), + }), + inputValidation: (input: PluginParams, config: ConfigParams) => { + const {numerator, denominator} = config; const schema = z .object({ @@ -119,39 +36,49 @@ export const Divide = ( return true; }); - const evaluatedInput = evaluateInput(input); - return validate>(schema, evaluatedInput); - }; + return validate>(schema, input); + }, + implementation: async (inputs: PluginParams[], config: ConfigParams) => { + const {numerator, denominator, output} = config; - /** - * Calculates the division of the given parameter. - */ - const calculateDivide = ( - input: PluginParams, - index: number, - params: { - numerator: number | string; - denominator: number | string; - } - ) => { - const {denominator, numerator} = params; - const finalDenominator = - typeof denominator === 'number' - ? denominator - : input[denominator] || denominator; - const finalNumerator = - typeof numerator === 'number' ? numerator : input[numerator]; - - if (finalDenominator === 0) { - console.warn(ZERO_DIVISION(Divide.name, index)); - return finalNumerator; - } - - return finalNumerator / finalDenominator; - }; + return inputs.map((input, index) => { + const calculatedResult = calculateDivide(input, index, { + numerator: input.numerator || numerator, + denominator: input.denominator || denominator, + }); - return { - metadata, - execute, - }; + return { + ...input, + [output]: calculatedResult, + }; + }); + }, + allowArithmeticExpressions: ['numerator', 'denominator'], +}); + +/** + * Calculates the division of the given parameter. + */ +const calculateDivide = ( + input: PluginParams, + index: number, + params: { + numerator: number | string; + denominator: number | string; + } +) => { + const {denominator, numerator} = params; + const finalDenominator = + typeof denominator === 'number' + ? denominator + : input[denominator] || denominator; + const finalNumerator = + typeof numerator === 'number' ? numerator : input[numerator]; + + if (finalDenominator === 0) { + console.warn(ZERO_DIVISION(Divide.name, index)); + return finalNumerator; + } + + return finalNumerator / finalDenominator; }; diff --git a/src/if-run/builtins/sci/index.ts b/src/if-run/builtins/sci/index.ts index 7e98a8f0..852faf2d 100644 --- a/src/if-run/builtins/sci/index.ts +++ b/src/if-run/builtins/sci/index.ts @@ -1,32 +1,15 @@ import {z} from 'zod'; -import { - ERRORS, - evaluateInput, - evaluateConfig, - evaluateArithmeticOutput, - validateArithmeticExpression, - getParameterFromArithmeticExpression, -} from '@grnsft/if-core/utils'; -import { - mapInputIfNeeded, - mapConfigIfNeeded, - mapOutputIfNeeded, -} from '@grnsft/if-core/utils/helpers'; -import { - ExecutePlugin, - PluginParams, - ConfigParams, - PluginParametersMetadata, - ParameterMetadata, - MappingParams, -} from '@grnsft/if-core/types'; -import {validate, allDefined} from '../../../common/util/validations'; +import {PluginFactory} from '@grnsft/if-core/interfaces'; +import {ConfigParams, PluginParams} from '@grnsft/if-core/types'; -import {STRINGS} from '../../config'; +import {validate} from '../../../common/util/validations'; + +import {ERRORS} from '@grnsft/if-core/utils'; + +import {allDefined} from '../../../common/util/validations'; -const {ConfigError} = ERRORS; -const {MISSING_CONFIG} = STRINGS; +import {STRINGS} from '../../config'; const {MissingInputDataError} = ERRORS; const { @@ -36,36 +19,28 @@ const { ZERO_DIVISION, } = STRINGS; -export const Sci = ( - config: ConfigParams, - parametersMetadata: PluginParametersMetadata, - mapping: MappingParams -): ExecutePlugin => { - const metadata = { - kind: 'execute', +export const Sci = PluginFactory({ + metadata: { inputs: { - ...({ - carbon: { - description: 'an amount of carbon emitted into the atmosphere', - unit: 'gCO2e', - 'aggregation-method': { - time: 'sum', - component: 'sum', - }, + 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', - }, + }, + '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', }, - } as ParameterMetadata), - ...parametersMetadata?.inputs, + }, }, - outputs: parametersMetadata?.outputs || { + outputs: { sci: { description: 'carbon expressed in terms of the given functional unit', unit: 'gCO2e', @@ -75,86 +50,22 @@ export const Sci = ( }, }, }, - }; - - /** - * Validates config. - */ - const validateConfig = () => { - if (!config) { - throw new ConfigError(MISSING_CONFIG); - } - - const mappedConfig = mapConfigIfNeeded(config, mapping); + }, + configValidation: (config: ConfigParams) => { const schema = z .object({ - 'functional-unit': z - .string() - .refine(param => - validateArithmeticExpression('functional-unit', param) - ), + 'functional-unit': z.string(), }) .refine(data => data['functional-unit'], { message: MISSING_FUNCTIONAL_UNIT_CONFIG, }); - return validate>(schema, mappedConfig); - }; - - /** - * Calculate the total emissions for a list of inputs. - */ - const execute = (inputs: PluginParams[]): PluginParams[] => { - const safeConfig = validateConfig(); + return validate>(schema, config); + }, + inputValidation: (input: PluginParams, config: ConfigParams) => { + const functionalUnit = config['functional-unit']; - return inputs.map((input, index) => { - const safeInput = Object.assign( - {}, - input, - validateInput(input, safeConfig) - ); - - const evaluatedConfig = evaluateConfig({ - config: safeConfig, - input: safeInput, - parametersToEvaluate: ['functional-unit'], - }); - const functionalUnit = isNaN(evaluatedConfig['functional-unit']) - ? safeInput[evaluatedConfig['functional-unit']] - : evaluatedConfig['functional-unit']; - - if (functionalUnit === 0) { - console.warn(ZERO_DIVISION(Sci.name, index)); - - return { - ...input, - ...safeInput, - sci: safeInput['carbon'], - }; - } - const calculatedResult = safeInput['carbon'] / functionalUnit; - - const result = { - ...input, - ...safeInput, - ...evaluateArithmeticOutput('sci', calculatedResult), - }; - - return mapOutputIfNeeded(result, mapping); - }); - }; - - /** - * Checks for fields in input. - */ - const validateInput = (input: PluginParams, safeConfig: ConfigParams) => { - const mappedInput = mapInputIfNeeded(input, mapping); - - const functionalUnit = getParameterFromArithmeticExpression( - safeConfig['functional-unit'] - ); - - if (!(functionalUnit in mappedInput && mappedInput[functionalUnit] >= 0)) { + if (!(functionalUnit in input && input[functionalUnit] >= 0)) { throw new MissingInputDataError(MISSING_FUNCTIONAL_UNIT_INPUT); } @@ -167,13 +78,29 @@ export const Sci = ( message: SCI_MISSING_FN_UNIT(config['functional-unit']), }); - const evaluatedInput = evaluateInput(mappedInput); + return validate>(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']; - return validate>(schema, evaluatedInput); - }; + if (functionalUnit === 0) { + console.warn(ZERO_DIVISION(Sci.name, index)); - return { - metadata, - execute, - }; -}; + return { + ...input, + sci: input['carbon'], + }; + } + const calculatedResult = input['carbon'] / functionalUnit; + + return { + ...input, + sci: calculatedResult, + }; + }); + }, + allowArithmeticExpressions: ['functional-unit'], +});