fix(build): Evaluate build operators in lowdefy.yaml

This commit is contained in:
Sam 2022-06-23 14:23:05 +02:00
parent c340b5237f
commit 49ed3e14fd
No known key found for this signature in database
GPG Key ID: D004126FCD1A6DF0
6 changed files with 121 additions and 20 deletions

View File

@ -24,7 +24,6 @@ function createSessionCallback({ authConfig, plugins }) {
});
async function sessionCallback({ session, token, user }) {
// console.log({ session, token, user });
if (token) {
const {
sub,
@ -74,6 +73,7 @@ function createSessionCallback({ authConfig, plugins }) {
}
for (const plugin of sessionCallbackPlugins) {
// eslint-disable-next-line no-param-reassign
session = await plugin.fn({
properties: plugin.properties ?? {},
session,

View File

@ -16,14 +16,21 @@
import recursiveBuild from './recursiveBuild.js';
import makeRefDefinition from './makeRefDefinition.js';
// TODO: build operators aren't evaluated in lowdefy.yaml file. Move recursive call up a layer or something.
import evaluateBuildOperators from './evaluateBuildOperators.js';
async function buildRefs({ context }) {
const components = await recursiveBuild({
const refDef = makeRefDefinition('lowdefy.yaml');
let components = await recursiveBuild({
context,
refDef: makeRefDefinition('lowdefy.yaml'),
refDef,
count: 0,
});
return components || {};
components = await evaluateBuildOperators({
context,
input: components,
refDef,
});
return components ?? {};
}
export default buildRefs;

View File

@ -19,6 +19,12 @@ import { jest } from '@jest/globals';
import buildRefs from './buildRefs.js';
import testContext from '../../test/testContext.js';
const mockLogWarn = jest.fn();
const logger = {
warn: mockLogWarn,
};
const readConfigFileMockImplementation = (files) => {
const mockImp = (filePath) => {
const file = files.find((file) => file.path === filePath);
@ -33,6 +39,7 @@ const readConfigFileMockImplementation = (files) => {
const mockReadConfigFile = jest.fn();
const context = testContext({
logger,
readConfigFile: mockReadConfigFile,
});
@ -1047,3 +1054,91 @@ _ref: target`,
});
});
});
describe('Evaluate build time operators', () => {
test('Evaluate build time operators in lowdefy.yaml', async () => {
const files = [
{
path: 'lowdefy.yaml',
content: `
answer:
_build.sum:
- 1
- 1`,
},
];
mockReadConfigFile.mockImplementation(readConfigFileMockImplementation(files));
const res = await buildRefs({ context });
expect(res).toEqual({
answer: 2,
});
});
test('Evaluate build time operators in referenced file', async () => {
const files = [
{
path: 'lowdefy.yaml',
content: `
answer:
_ref: file.yaml`,
},
{
path: 'file.yaml',
content: `
_build.sum:
- 1
- 1`,
},
];
mockReadConfigFile.mockImplementation(readConfigFileMockImplementation(files));
const res = await buildRefs({ context });
expect(res).toEqual({
answer: 2,
});
});
test('Build time operator error in lowdefy.yaml', async () => {
const files = [
{
path: 'lowdefy.yaml',
content: `
answer:
_build.sum: A`,
},
];
mockReadConfigFile.mockImplementation(readConfigFileMockImplementation(files));
const res = await buildRefs({ context });
expect(res).toEqual({
answer: null,
});
expect(mockLogWarn.mock.calls).toEqual([
['Build operator errors.'],
['Operator Error: _sum takes an array type as input. Received: "A" at lowdefy.yaml.'],
]);
});
test('Build time operator error in referenced file', async () => {
const files = [
{
path: 'lowdefy.yaml',
content: `
answer:
_ref: file.yaml`,
},
{
path: 'file.yaml',
content: `
_build.sum: A`,
},
];
mockReadConfigFile.mockImplementation(readConfigFileMockImplementation(files));
const res = await buildRefs({ context });
expect(res).toEqual({
answer: null,
});
expect(mockLogWarn.mock.calls).toEqual([
['Build operator errors.'],
['Operator Error: _sum takes an array type as input. Received: "A" at file.yaml.'],
]);
});
});

View File

@ -25,12 +25,8 @@ async function recursiveParseFile({ context, refDef, count, referencedFrom }) {
throw new Error(`Maximum recursion depth of references exceeded.`);
}
let fileContent = await getRefContent({ context, refDef, referencedFrom });
const parsedFileContent = await evaluateBuildOperators({
context,
input: fileContent,
refDef: { path: 'lowdefy.yaml' },
});
const { foundRefs, fileContentBuiltRefs } = getRefsFromFile(parsedFileContent);
const { foundRefs, fileContentBuiltRefs } = getRefsFromFile(fileContent);
const parsedFiles = {};
@ -39,7 +35,6 @@ async function recursiveParseFile({ context, refDef, count, referencedFrom }) {
// To do this, since foundRefs is an array of ref definitions that are in order of the
// deepest nodes first we for loop over over foundRefs one by one, awaiting each result.
// eslint-disable-next-line no-restricted-syntax
for (const newRefDef of foundRefs.values()) {
// Parse vars and path before passing down to parse new file
const parsedRefDef = populateRefs({
@ -55,19 +50,20 @@ async function recursiveParseFile({ context, refDef, count, referencedFrom }) {
referencedFrom: refDef.path,
});
const evaluatedOperators = await evaluateBuildOperators({
const transformedFile = await runTransformer({
context,
input: parsedFile,
refDef: parsedRefDef,
});
const transformedFile = await runTransformer({
// Evaluated in recursive loop for better error messages
const evaluatedOperators = await evaluateBuildOperators({
context,
input: evaluatedOperators,
input: transformedFile,
refDef: parsedRefDef,
});
parsedFiles[newRefDef.id] = transformedFile;
parsedFiles[newRefDef.id] = evaluatedOperators;
}
return populateRefs({
toPopulate: fileContentBuiltRefs,

View File

@ -17,15 +17,18 @@
import { serializer, type } from '@lowdefy/helpers';
class NodeParser {
constructor({ env, payload, secrets, user, operators }) {
constructor({ env, payload, secrets, user, operators, verbose }) {
this.env = env;
this.operators = operators;
this.payload = payload;
this.secrets = secrets;
this.user = user;
this.parse = this.parse.bind(this);
this.verbose;
}
// TODO: Look at logging here
// TODO: Remove console.error = () => {}; from tests
parse({ args, input, location, operatorPrefix = '_' }) {
if (type.isUndefined(input)) {
return { output: input, errors: [] };
@ -63,7 +66,9 @@ class NodeParser {
return res;
} catch (e) {
errors.push(e);
console.error(e);
if (this.verbose) {
console.error(e);
}
return null;
}
};

View File

@ -17,8 +17,6 @@
/* eslint-disable max-classes-per-file */
import NodeParser from './nodeParser.js';
console.error = () => {};
const args = [{ args: true }];
const operators = {