feat(scaffolder): add support for parsing the valuues as a json object in the parameters

Signed-off-by: blam <ben@blam.sh>
This commit is contained in:
blam
2021-04-13 19:38:44 +02:00
parent c10e6490ca
commit c2a685ddb1
2 changed files with 103 additions and 8 deletions
@@ -41,20 +41,24 @@ async function createStore(): Promise<DatabaseTaskStore> {
describe('TaskWorker', () => {
let storage: DatabaseTaskStore;
let actionRegistry = new TemplateActionRegistry();
beforeAll(async () => {
storage = await createStore();
});
const logger = getVoidLogger();
const actionRegistry = new TemplateActionRegistry();
actionRegistry.register({
id: 'test-action',
handler: async ctx => {
ctx.output('testOutput', 'winning');
},
beforeEach(() => {
actionRegistry = new TemplateActionRegistry();
actionRegistry.register({
id: 'test-action',
handler: async ctx => {
ctx.output('testOutput', 'winning');
},
});
});
const logger = getVoidLogger();
it('should fail when action does not exist', async () => {
const broker = new StorageTaskBroker(storage, logger);
const taskWorker = new TaskWorker({
@@ -166,4 +170,83 @@ describe('TaskWorker', () => {
const event = events.find(e => e.type === 'completion');
expect((event?.body?.output as JsonObject).result).toBe('winning');
});
it('should parse strings as objects if possible', async () => {
const inputAction = createTemplateAction<{
address: { line1: string };
address2: string;
}>({
id: 'test-input',
schema: {
input: {
type: 'object',
required: ['address'],
properties: {
address: {
title: 'address',
description: 'Enter name',
type: 'object',
properties: {
line1: {
type: 'string',
},
},
},
address2: {
type: 'string',
},
},
},
},
async handler(ctx) {
if (ctx.input.address.line1 !== 'line 1') {
throw new Error(
`expected address.line1 to be "line 1" got ${ctx.input.address.line1}`,
);
}
if (ctx.input.address2 !== '{"not valid"}') {
throw new Error(
`expected address2 to be "{"not valid"}" got ${ctx.input.address2}`,
);
}
ctx.output('address', ctx.input.address.line1);
},
});
actionRegistry.register(inputAction);
const broker = new StorageTaskBroker(storage, logger);
const taskWorker = new TaskWorker({
logger,
workingDirectory: os.tmpdir(),
actionRegistry,
taskBroker: broker,
});
const { taskId } = await broker.dispatch({
steps: [
{
id: 'test-input',
name: 'test-input',
action: 'test-input',
input: {
address: JSON.stringify({ line1: 'line 1' }),
address2: '{"not valid"}',
},
},
],
output: {
result: '{{ steps.test-input.output.address }}',
},
values: {},
});
const task = await broker.claim();
await taskWorker.runOneTask(task);
const { events } = await storage.listEvents({ taskId });
const event = events.find(e => e.type === 'completion');
expect((event?.body?.output as JsonObject).result).toBe('line 1');
});
});
@@ -102,13 +102,25 @@ export class TaskWorker {
step.input &&
JSON.parse(JSON.stringify(step.input), (_key, value) => {
if (typeof value === 'string') {
return handlebars.compile(value, {
const templated = handlebars.compile(value, {
noEscape: true,
strict: true,
data: false,
preventIndent: true,
})(templateCtx);
// If it smells like a JSON object then give it a parse as an object and if it fails return the string
if (templated.startsWith('{') && templated.endsWith('}')) {
try {
// Don't recursively JSON parse the values of this string. Shouldn't need to, don't want to encourage the use of returning handlebars from somewhere else
return JSON.parse(templated);
} catch {
return templated;
}
}
return templated;
}
return value;
});