Skip to content

Commit

Permalink
feat: add validation for configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
waynevanson committed Aug 26, 2023
1 parent baeba07 commit a0f753c
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 40 deletions.
1 change: 1 addition & 0 deletions packages/data-entry/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
"dayjs": "^1.11.9",
"dequal": "^2.0.3",
"fp-ts": "^2.16.1",
"io-ts": "^2.2.20",
"preact": "^10.17.1",
"styled-components": "^6.0.7"
},
Expand Down
85 changes: 85 additions & 0 deletions packages/data-entry/src/common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { JsonSchema, UISchemaElement } from '@jsonforms/core';
import { readonlyRecord, string } from 'fp-ts';
import { Monoid } from 'fp-ts/lib/Monoid';
import { pipe } from 'fp-ts/lib/function';
import * as codec from 'io-ts/Codec';
import { Codec, InputOf, OutputOf, TypeOf } from 'io-ts/Codec';
import * as decoder from 'io-ts/Decoder';
import { Decoder } from 'io-ts/Decoder';
import { Encoder } from 'io-ts/Encoder';

export type Datasource = Sum<{
file: string;
}>;

export interface Configuration {
datasource: Datasource;
forms: {
schema: JsonSchema;
uischema?: UISchemaElement;
};
}

export type Sum<T extends Record<string, unknown>> = keyof T extends never
? never
: {
[P in keyof T]: Record<P, T[P]>;
}[keyof T];

const decoderMonoid = <I, A>(error: string): Monoid<Decoder<I, A>> => ({
empty: decoder.fromRefinement((i): i is never => false, error),
concat: (x, y) => decoder.Alt.alt(x, () => y),
});

const decoderSumMonoid = <P>() =>
decoderMonoid<
{ [K in keyof P]: Record<K, decoder.InputOf<P[K]>> }[keyof P],
{ [K in keyof P]: Record<K, decoder.TypeOf<P[K]>> }[keyof P]
>('Sum');

// fix this then all good right?
const decoderSum = <P extends Record<string, Decoder<unknown, unknown>>>(
properties: keyof P extends never ? never : P,
): Decoder<
{ [K in keyof P]: Record<K, decoder.InputOf<P[K]>> }[keyof P],
{ [K in keyof P]: Record<K, decoder.TypeOf<P[K]>> }[keyof P]
> =>
pipe(
properties,
readonlyRecord.fromRecord,
readonlyRecord.mapWithIndex((property, value) =>
decoder.struct({ [property]: value }),
),
readonlyRecord.foldMap(string.Ord)(decoderSumMonoid<P>())(
(de) => de as never,
),
);

// todo - fix, but with we're not encoding anything so should be okay.
const encoderSum = <P extends Record<string, Codec<unknown, unknown, unknown>>>(
properties: keyof P extends never ? never : P,
): Encoder<
{ [K in keyof P]: Record<K, OutputOf<P[K]>> }[keyof P],
{ [K in keyof P]: Record<K, TypeOf<P[K]>> }[keyof P]
> => ({}) as never;

const sum = <P extends Record<string, Codec<unknown, unknown, unknown>>>(
properties: keyof P extends never ? never : P,
): Codec<
{ [K in keyof P]: Record<K, InputOf<P[K]>> }[keyof P],
{ [K in keyof P]: Record<K, OutputOf<P[K]>> }[keyof P],
{ [K in keyof P]: Record<K, TypeOf<P[K]>> }[keyof P]
> => ({
decode: decoderSum(properties).decode as never,
encode: encoderSum(properties).encode,
});

/// schema

export const configuration = codec.struct({
datasource: sum({ file: codec.string }),
forms: pipe(
codec.struct({ schema: codec.UnknownRecord }),
codec.intersect(codec.partial({ uischema: codec.UnknownRecord })),
),
});
21 changes: 0 additions & 21 deletions packages/data-entry/src/common.tsx

This file was deleted.

1 change: 0 additions & 1 deletion packages/data-entry/src/components/context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ export interface MainProps {
vault: Vault;
schema: JsonSchema;
uischema?: UISchemaElement;
submit?: string;
fileName: string;
}

Expand Down
36 changes: 19 additions & 17 deletions packages/data-entry/src/plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,22 @@ import {
import * as React from 'react';
import { StrictMode } from 'react';
import { Root, createRoot } from 'react-dom/client';
import { Configuration } from './common';
import { configuration, Configuration } from './common';
import * as decoder from 'io-ts/Decoder';
import { ThemeProvider } from '@mui/material';
import { ApplicationProvider } from './components/context';
import { Application } from './components';
import { useTheme } from './components/material';
import { either } from 'fp-ts';
import { flow, pipe } from 'fp-ts/lib/function';

type Handler = Parameters<Plugin['registerMarkdownCodeBlockProcessor']>[1];

const notify = (error: any) => {
new Notice(error);
return error as never;
};

export class MainPlugin extends Plugin {
async onload(): Promise<void> {
this.registerMarkdownCodeBlockProcessors();
Expand All @@ -43,21 +51,26 @@ export class MainPlugin extends Plugin {
yamls: ReadonlyArray<string>,
): Handler {
return async (source, element, context) => {
const jsonify = noticify(
const jsonify = either.tryCatchK(
yamls.includes(extension) ? parseYaml : JSON.parse,
(error) => error,
);

const json = pipe(
jsonify(source),
either.chain(flow(configuration.decode, either.mapLeft(decoder.draw))),
either.getOrElseW(notify),
);
const json = jsonify(source) as Configuration;

const Component = () => (
<StrictMode>
<ThemeProvider theme={useTheme()}>
<ApplicationProvider
value={{
fileName: (json.datasource as Record<string, string>).file,
fileName: json.datasource.file,
vault: this.app.vault,
schema: json.forms.schema,
uischema: json.forms.uischema,
submit: json.submit,
uischema: json.forms.uischema as never,
}}
>
<Application />
Expand Down Expand Up @@ -93,17 +106,6 @@ class ReactMarkdownRenderChild extends MarkdownRenderChild {
}
}

const noticify =
<P extends Array<unknown>, A>(f: (...args: P) => A) =>
(...args: P): A | null => {
try {
return f(...args);
} catch (error) {
new Notice(error);
return null;
}
};

const removeCodeFence = (string: string) => {
const regex = /(?:```)(?<type>.*)\n(?<content>[^`]+)\n(?:```)/;
const groups = regex.exec(string)?.groups as
Expand Down
25 changes: 24 additions & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit a0f753c

Please sign in to comment.