Skip to content

Commit

Permalink
Parse/validate Blueprint JSON
Browse files Browse the repository at this point in the history
  • Loading branch information
danielnaab committed Nov 7, 2024
1 parent 846e0c2 commit 367dcaf
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 18 deletions.
6 changes: 3 additions & 3 deletions packages/forms/src/blueprint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,11 @@ export const createForm = (
patterns: [
{
id: 'root',
type: 'sequence',
type: 'page-set',
data: {
patterns: [],
pages: [],
},
} satisfies SequencePattern,
} satisfies PageSetPattern,
],
root: 'root',
}
Expand Down
62 changes: 60 additions & 2 deletions packages/forms/src/builder/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { type VoidResult } from '@atj/common';
import * as z from 'zod';

import { failure, success, type Result, type VoidResult } from '@atj/common';
import {
addPageToPageSet,
addPatternToFieldset,
Expand All @@ -24,7 +26,63 @@ import { type FieldsetPattern } from '../patterns/fieldset/config.js';
import { type PageSetPattern } from '../patterns/page-set/config.js';
import type { Blueprint, FormSummary } from '../types.js';
import type { ParsedPdf } from '../documents/pdf/parsing-api.js';
import type { DocumentFieldMap } from '../documents/types.js';

const createFormSchema = (config: FormConfig) => {
return z.object({
summary: z.object({
title: z.string(),
description: z.string(),
}),
root: z.string(),
patterns: z.record(
z.string(),
z.any().refine(
val => {
const patternConfig = config.patterns[val?.type];
if (!patternConfig) {
return false;
}
const result = patternConfig.parseConfigData(val?.data);
if (!result.success) {
const message = Object.values(result.error)
.map(err => err.message || '')
.join(', ');
console.error(val?.type, result.error);
console.error(`Pattern config error: ${message}`);
}
return result.success;
},
{
message: 'Invalid pattern',
}
)
),
outputs: z.array(
z.object({
id: z.string(),
path: z.string(),
fields: z.record(z.string(), z.any()),
formFields: z.record(z.string(), z.string()),
})
),
});
};

export const parseForm = (config: FormConfig, obj: any): Result<Blueprint> => {
const formSchema = createFormSchema(config);
const result = formSchema.safeParse(obj);
if (result.error) {
return failure(result.error.message);
}
return success(result.data);
};

export const parseFormString = (
config: FormConfig,
json: string
): Result<Blueprint> => {
return parseForm(config, JSON.parse(json));
};

export class BlueprintBuilder {
bp: Blueprint;
Expand Down
5 changes: 2 additions & 3 deletions packages/forms/src/repository/get-form.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,14 @@ describeDatabase('getForm', () => {
.insertInto('forms')
.values({
id: '45c66187-64e2-4d75-a45a-e80f1d035bc5',
data: '{"summary":{"title":"Title","description":"Description"},"root":"root","patterns":{"root":{"type":"sequence","id":"root","data":{"patterns":[]}}},"outputs":[{"id":"test-id","path":"test.pdf","fields":{},"formFields":{}}]}',
data: '{"summary":{"title":"Title","description":"Description"},"root":"root","patterns":{"root":{"type":"page-set","id":"root","data":{"pages":[]}}},"outputs":[{"id":"test-id","path":"test.pdf","fields":{},"formFields":{}}]}',
})
.execute();

const result = await getForm(
db.ctx,
'45c66187-64e2-4d75-a45a-e80f1d035bc5'
);
console.log(result);
expect(result).toEqual(TEST_FORM);
});

Expand All @@ -36,7 +35,7 @@ describeDatabase('getForm', () => {
const TEST_FORM: Blueprint = {
summary: { title: 'Title', description: 'Description' },
root: 'root',
patterns: { root: { type: 'sequence', id: 'root', data: { patterns: [] } } },
patterns: { root: { type: 'page-set', id: 'root', data: { pages: [] } } },
outputs: [
{
id: 'test-id',
Expand Down
6 changes: 1 addition & 5 deletions packages/forms/src/repository/get-form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,5 @@ export const getForm: GetForm = async (ctx, formId) => {
return null;
}

return parseStringForm(selectResult.data);
};

const parseStringForm = (formString: string): Blueprint => {
return JSON.parse(formString);
return JSON.parse(selectResult.data);
};
2 changes: 1 addition & 1 deletion packages/forms/src/services/get-form.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ describe('getForm', () => {

const result = await getForm(ctx, addResult.data.id);
if (!result.success) {
expect.fail('Failed to add form:', result.error);
expect.fail(`Failed to get form: ${JSON.stringify(result.error)}`);
}
expect(result.data).toEqual(TEST_FORM);
});
Expand Down
14 changes: 12 additions & 2 deletions packages/forms/src/services/get-form.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { type Result, failure, success } from '@atj/common';

import { type Blueprint } from '../index.js';
import { parseForm } from '../builder/index.js';
import { type FormServiceContext } from '../context/index.js';
import { type Blueprint } from '../types.js';

type GetFormError = {
status: number;
Expand All @@ -21,5 +22,14 @@ export const getForm: GetForm = async (ctx, formId) => {
message: 'Form not found',
});
}
return success(result);

const parseResult = parseForm(ctx.config, result);
if (!parseResult.success) {
return failure({
status: 500,
message: parseResult.error,
});
}

return success(parseResult.data);
};
14 changes: 12 additions & 2 deletions packages/forms/src/services/save-form.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { type Result, failure, success } from '@atj/common';
import { Blueprint } from '../index.js';

import { type FormServiceContext } from '../context/index.js';
import { type Blueprint } from '../types.js';
import { parseForm } from '../builder/index.js';

type SaveFormError = {
status: number;
Expand All @@ -21,7 +22,16 @@ export const saveForm: SaveForm = async (ctx, formId, form) => {
message: 'You must be logged in to save a form',
});
}
const result = await ctx.repository.saveForm(formId, form);

const parseResult = parseForm(ctx.config, form);
if (!parseResult.success) {
return failure({
status: 422,
message: parseResult.error,
});
}

const result = await ctx.repository.saveForm(formId, parseResult.data);
if (result.success === false) {
return failure({
status: 500,
Expand Down

0 comments on commit 367dcaf

Please sign in to comment.