Skip to content

Commit cf83951

Browse files
Merge pull request #1032 from Green-Software-Foundation/refactor-plugins
Refactor plugins
2 parents 9e08d52 + b889285 commit cf83951

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1869
-2682
lines changed

Refactor-migration-guide.md

Lines changed: 63 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -199,65 +199,76 @@ Details tbc...
199199
200200
## Plugins
201201
202-
The plugins themselves require some changes to keep them compatible with the refactored IF.
202+
Plugins require some modifications to remain compatible with the refactored IF interface.
203203
204-
Instead of the old class-based model, plugins are now functions. They conform to the following interface:
204+
Each plugin follows the `PluginFactory` interface, which is a higher-order function that accepts a `params` object of type `PluginFactoryParams`. This function returns another function (the inner function), which handles the plugin’s `config`, `parametersMetadata`, and `mapping`.
205205
206206
```ts
207-
export type PluginInterface = {
208-
execute: (inputs: PluginParams[]) => PluginParams[];
209-
metadata: {
210-
kind: string;
211-
};
212-
[key: string]: any;
213-
};
207+
export const PluginFactory =
208+
(params: PluginFactoryParams) =>
209+
(
210+
config: ConfigParams = {},
211+
parametersMetadata: PluginParametersMetadata,
212+
mapping: MappingParams
213+
) => ({
214+
metadata: {
215+
kind: 'execute',
216+
inputs: {...params.metadata.inputs, ...parametersMetadata?.inputs},
217+
outputs: parametersMetadata?.outputs || params.metadata.outputs,
218+
},
219+
execute: async (inputs: PluginParams[]) => {
220+
// Generic plugin functionality goes here
221+
// E.g., mapping, arithmetic operations, validation
222+
// Process inputs and mapping logic
223+
});
224+
})
214225
```
215226
216-
The plugin still requires an execute function. This is where you implement the plugin logic.
227+
Inner Function Parameters:
228+
229+
- `config`: This is of type `ConfigParams` and has a default value of an empty object ({}). This might hold configuration settings for the plugin.
230+
- `parametersMetadata`: A `PluginParametersMetadata` object that describes the metadata for the plugin’s parameters.
231+
- `mapping`: A `MappingParams` object, describing parameters are mapped.
232+
233+
Implementation Function:
217234
218-
Here's a minimal example for a plugin that sums some inputs defined in config - see inline comments for some important notes:
235+
The plugin requires an `implementation` function, where the actual plugin logic is defined.
236+
Here’s a minimal example of a plugin that sums inputs as defined in the config. See the inline comments for further clarification.
219237
220238
```ts
221-
// Here's the function definition - notice that config is passed in here!
222-
export const Sum = (config: SumConfig): PluginInterface => {
223-
const inputParameters = config['input-parameters'] || [];
224-
const outputParameter = config['output-parameter'];
225-
226-
// we also return metadata now too - you can add more or just use this default
227-
const metadata = {
228-
kind: 'execute',
229-
};
230-
231-
/**
232-
* Calculate the sum of the input metrics for each timestamp.
233-
*/
234-
const execute = async (inputs: PluginParams[]): Promise<PluginParams[]> => {
235-
inputs.map(input => {
236-
return calculateSum(input, inputParameters, outputParameter);
239+
// Here's the function definition!
240+
export const Sum = PluginFactory({
241+
configValidation: z.object({
242+
'input-parameters': z.array(z.string()),
243+
'output-parameter': z.string().min(1),
244+
}),
245+
inputValidation: (input: PluginParams, config: ConfigParams) => {
246+
return validate(validationSchema, inputData);
247+
},
248+
implementation: async (inputs: PluginParams[], config: ConfigParams) => {
249+
const {
250+
'input-parameters': inputParameters,
251+
'output-parameter': outputParameter,
252+
} = config;
253+
254+
return inputs.map(input => {
255+
const calculatedResult = calculateSum(input, inputParameters);
256+
257+
return {
258+
...input,
259+
[outputParameter]: calculatedResult,
260+
};
237261
});
238-
return inputs;
239-
};
240-
241-
/**
242-
* Calculates the sum of the energy components.
243-
*/
244-
const calculateSum = (
245-
input: PluginParams,
246-
inputParameters: string[],
247-
outputParameter: string
248-
) => {
249-
input[outputParameter] = inputParameters.reduce(
250-
(accumulator, metricToSum) => {
251-
return accumulator + input[metricToSum];
252-
},
253-
0
254-
);
255-
};
256-
257-
// return the metadata and the execute function
258-
return {
259-
metadata,
260-
execute,
261-
};
262-
};
262+
},
263+
allowArithmeticExpressions: [],
264+
});
265+
266+
/**
267+
* Calculates the sum of the energy components.
268+
*/
269+
const calculateSum = (input: PluginParams, inputParameters: string[]) =>
270+
inputParameters.reduce(
271+
(accumulator, metricToSum) => accumulator + input[metricToSum],
272+
0
273+
);
263274
```

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"dependencies": {
2121
"@commitlint/cli": "^18.6.0",
2222
"@commitlint/config-conventional": "^18.6.0",
23-
"@grnsft/if-core": "^0.0.23",
23+
"@grnsft/if-core": "^0.0.24",
2424
"axios": "^1.7.2",
2525
"csv-parse": "^5.5.6",
2626
"csv-stringify": "^6.4.6",

src/__tests__/if-run/builtins/coefficient.test.ts

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import {ERRORS} from '@grnsft/if-core/utils';
33
import {Coefficient} from '../../../if-run/builtins/coefficient';
44

55
import {STRINGS} from '../../../if-run/config';
6-
import {CoefficientConfig} from '@grnsft/if-core/types';
76

87
const {InputValidationError, ConfigError} = ERRORS;
98
const {MISSING_CONFIG} = STRINGS;
@@ -29,7 +28,7 @@ describe('builtins/coefficient: ', () => {
2928
});
3029

3130
describe('execute(): ', () => {
32-
it('successfully applies coefficient strategy to given input.', () => {
31+
it('successfully applies coefficient strategy to given input.', async () => {
3332
expect.assertions(1);
3433

3534
const expectedResult = [
@@ -41,7 +40,7 @@ describe('builtins/coefficient: ', () => {
4140
},
4241
];
4342

44-
const result = coefficient.execute([
43+
const result = await coefficient.execute([
4544
{
4645
duration: 3600,
4746
carbon: 3,
@@ -54,7 +53,7 @@ describe('builtins/coefficient: ', () => {
5453
expect(result).toStrictEqual(expectedResult);
5554
});
5655

57-
it('succcessfully executes when the mapping has data.', () => {
56+
it('succcessfully executes when the mapping has data.', async () => {
5857
const mapping = {
5958
carbon: 'carbon-for-production',
6059
};
@@ -71,7 +70,7 @@ describe('builtins/coefficient: ', () => {
7170
},
7271
];
7372

74-
const result = coefficient.execute([
73+
const result = await coefficient.execute([
7574
{
7675
duration: 3600,
7776
'carbon-for-production': 3,
@@ -84,7 +83,7 @@ describe('builtins/coefficient: ', () => {
8483
expect(result).toStrictEqual(expectedResult);
8584
});
8685

87-
it('succcessfully executes when the mapping map output parameter.', () => {
86+
it('succcessfully executes when the mapping map output parameter.', async () => {
8887
const mapping = {
8988
'carbon-product': 'carbon-result',
9089
};
@@ -101,7 +100,7 @@ describe('builtins/coefficient: ', () => {
101100
},
102101
];
103102

104-
const result = coefficient.execute([
103+
const result = await coefficient.execute([
105104
{
106105
duration: 3600,
107106
carbon: 3,
@@ -114,7 +113,7 @@ describe('builtins/coefficient: ', () => {
114113
expect(result).toStrictEqual(expectedResult);
115114
});
116115

117-
it('successfully executes when a parameter has an arithmetic expression.', () => {
116+
it('successfully executes when a parameter has an arithmetic expression.', async () => {
118117
expect.assertions(1);
119118
const config = {
120119
'input-parameter': '=3*carbon',
@@ -136,7 +135,7 @@ describe('builtins/coefficient: ', () => {
136135
},
137136
];
138137

139-
const result = coefficient.execute([
138+
const result = await coefficient.execute([
140139
{
141140
duration: 3600,
142141
carbon: 3,
@@ -149,7 +148,7 @@ describe('builtins/coefficient: ', () => {
149148
expect(result).toStrictEqual(expectedResult);
150149
});
151150

152-
it('throws an error when the `coefficient` has wrong arithmetic expression.', () => {
151+
it('throws an error when the `coefficient` has wrong arithmetic expression.', async () => {
153152
const config = {
154153
'input-parameter': 'carbon',
155154
coefficient: 'mock-param',
@@ -159,16 +158,12 @@ describe('builtins/coefficient: ', () => {
159158
inputs: {},
160159
outputs: {},
161160
};
162-
const coefficient = Coefficient(
163-
config as any as CoefficientConfig,
164-
parametersMetadata,
165-
{}
166-
);
161+
const coefficient = Coefficient(config, parametersMetadata, {});
167162

168163
expect.assertions(2);
169164

170165
try {
171-
coefficient.execute([
166+
await coefficient.execute([
172167
{
173168
duration: 3600,
174169
carbon: 'some-param',
@@ -185,14 +180,14 @@ describe('builtins/coefficient: ', () => {
185180
}
186181
});
187182

188-
it('throws an error when config is not provided.', () => {
183+
it('throws an error when config is not provided.', async () => {
189184
const config = undefined;
190185
const coefficient = Coefficient(config!, parametersMetadata, {});
191186

192187
expect.assertions(1);
193188

194189
try {
195-
coefficient.execute([
190+
await coefficient.execute([
196191
{
197192
duration: 3600,
198193
timestamp: '2021-01-01T00:00:00Z',
@@ -204,7 +199,7 @@ describe('builtins/coefficient: ', () => {
204199
}
205200
});
206201

207-
it('throws an error on missing `input-parameter` param in input.', () => {
202+
it('throws an error on missing `input-parameter` param in input.', async () => {
208203
const invalidConfig = {
209204
'input-parameter': '',
210205
coefficient: 3,
@@ -217,7 +212,7 @@ describe('builtins/coefficient: ', () => {
217212
expect.assertions(1);
218213

219214
try {
220-
coefficient.execute([
215+
await coefficient.execute([
221216
{
222217
duration: 3600,
223218
timestamp: '2021-01-01T00:00:00Z',
@@ -231,7 +226,7 @@ describe('builtins/coefficient: ', () => {
231226
}
232227
});
233228

234-
it('throws an error on missing `output-parameter` param in input.', () => {
229+
it('throws an error on missing `output-parameter` param in input.', async () => {
235230
const invalidConfig = {
236231
'input-parameter': 'carbon',
237232
coefficient: 10,
@@ -243,7 +238,7 @@ describe('builtins/coefficient: ', () => {
243238

244239
expect.assertions(1);
245240
try {
246-
coefficient.execute([
241+
await coefficient.execute([
247242
{
248243
duration: 3600,
249244
timestamp: '2021-01-01T00:00:00Z',

0 commit comments

Comments
 (0)