Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/async-advanced-fields #253

Merged
merged 5 commits into from
May 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 41 additions & 41 deletions esbuild.config.mjs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import esbuild from "esbuild";
import process from "process";
import builtins from "builtin-modules";
import esbuild from "esbuild";
import esbuildSvelte from "esbuild-svelte";
import fs from "node:fs";
import process from "process";
import sveltePreprocess from "svelte-preprocess";
import fs from 'node:fs';

const banner = `/*
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
Expand All @@ -14,46 +14,46 @@ if you want to view the source, please visit the github repository of this plugi
const prod = process.argv[2] === "production";

const context = await esbuild.context({
banner: {
js: banner,
},
entryPoints: ["src/main.ts"],
bundle: true,
metafile: true,
plugins: [
esbuildSvelte({
compilerOptions: { css: "injected" },
preprocess: sveltePreprocess(),
}),
],
external: [
"obsidian",
"electron",
"@codemirror/autocomplete",
"@codemirror/collab",
"@codemirror/commands",
"@codemirror/language",
"@codemirror/lint",
"@codemirror/search",
"@codemirror/state",
"@codemirror/view",
"@lezer/common",
"@lezer/highlight",
"@lezer/lr",
...builtins,
],
format: "cjs",
target: "es2018",
logLevel: "info",
sourcemap: prod ? false : "inline",
treeShaking: true,
outfile: "main.js",
banner: {
js: banner,
},
entryPoints: ["src/main.ts"],
bundle: true,
metafile: true,
plugins: [
esbuildSvelte({
compilerOptions: { css: "injected" },
preprocess: sveltePreprocess(),
}),
],
external: [
"obsidian",
"electron",
"@codemirror/autocomplete",
"@codemirror/collab",
"@codemirror/commands",
"@codemirror/language",
"@codemirror/lint",
"@codemirror/search",
"@codemirror/state",
"@codemirror/view",
"@lezer/common",
"@lezer/highlight",
"@lezer/lr",
...builtins,
],
format: "cjs",
target: "es2019",
logLevel: "info",
sourcemap: prod ? false : "inline",
treeShaking: true,
outfile: "main.js",
});

if (prod) {
const result = await context.rebuild();
fs.writeFileSync('meta.json', JSON.stringify(result.metafile))
process.exit(0);
const result = await context.rebuild();
fs.writeFileSync("meta.json", JSON.stringify(result.metafile));
process.exit(0);
} else {
await context.watch();
await context.watch();
}
4 changes: 2 additions & 2 deletions manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"author": "Danielo Rodriguez",
"authorUrl": "https://danielo.es",
"fundingUrl": "https://www.buymeacoffee.com/danielo515",
"helpUrl": "https://danielorodriguez.com/obsidian-modal-form/",
"helpUrl": "https://danielorodriguez.com/obsidian-modal-form/",
"isDesktopOnly": false,
"version": "1.40.4"
}
}
4 changes: 2 additions & 2 deletions package-lock.json

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

34 changes: 19 additions & 15 deletions src/FormModal.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import { App, Modal, Platform, Setting, sanitizeHTMLToDom } from "obsidian";
import { E, absurd, parseFunctionBody, pipe, throttle } from "@std";
import * as R from "fp-ts/Record";
import MultiSelect from "./views/components/MultiSelect.svelte";
import * as TE from "fp-ts/TaskEither";
import { App, Modal, Platform, Setting, sanitizeHTMLToDom } from "obsidian";
import { SvelteComponent } from "svelte";
import { Writable } from "svelte/store";
import FormResult, { type ModalFormData } from "./core/FormResult";
import { formDataFromFormDefaults } from "./core/formDataFromFormDefaults";
import { get_tfiles_from_folder } from "./utils/files";
import type { FormDefinition, FormOptions } from "./core/formDefinition";
import { FieldValue, FormEngine, makeFormEngine } from "./store/formStore";
import { FileSuggest } from "./suggesters/suggestFile";
import { FolderSuggest } from "./suggesters/suggestFolder";
import { DataviewSuggest } from "./suggesters/suggestFromDataview";
import { SvelteComponent } from "svelte";
import { E, parseFunctionBody, pipe, throttle, absurd } from "@std";
import { log_error, log_notice } from "./utils/Log";
import { FieldValue, FormEngine, makeFormEngine } from "./store/formStore";
import { Writable } from "svelte/store";
import { FolderSuggest } from "./suggesters/suggestFolder";
import { get_tfiles_from_folder } from "./utils/files";
import MultiSelect from "./views/components/MultiSelect.svelte";
import { MultiSelectModel, MultiSelectTags } from "./views/components/MultiSelectModel";

export type SubmitFn = (formResult: FormResult) => void;
Expand Down Expand Up @@ -190,10 +191,12 @@ export class FormModal extends Modal {
values: fieldStore.value as Writable<string[]>,
setting: fieldBase,
errors: fieldStore.errors,
model: MultiSelectTags(
fieldInput,
this.app,
fieldStore.value as Writable<string[]>,
model: Promise.resolve(
MultiSelectTags(
fieldInput,
this.app,
fieldStore.value as Writable<string[]>,
),
),
},
}),
Expand Down Expand Up @@ -257,21 +260,22 @@ export class FormModal extends Modal {
const sub = this.formEngine.subscribe((form) => {
pipe(
functionParsed,
E.chainW((fn) =>
TE.fromEither,
TE.chainW((fn) =>
pipe(
form.fields,
R.filterMap((field) => field.value),
fn,
),
),
E.match(
TE.match(
(error) => {
console.error(error);
notifyError("Error in document block")(String(error));
},
(newText) => domNode.setText(sanitizeHTMLToDom(newText)),
),
);
)();
});
return this.subscriptions.push(sub);
}
Expand Down
33 changes: 25 additions & 8 deletions src/std/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as TE from "fp-ts/TaskEither";
import { array, boolean, number, object, string } from "valibot";
import { E, parseFunctionBody, pipe, trySchemas } from "./index";
import { string, number, array, boolean, object } from "valibot";

describe("trySchemas", () => {
const schema1 = object({
Expand Down Expand Up @@ -121,21 +122,37 @@ describe("parseFunctionBody", () => {
);
});
it("should fail to parse a function body when it is incorrect", () => {
const input = "{ return x + 1; ";
const input = "% return x + 1; ";
const result = parseFunctionBody(input);
expect(result).toEqual(E.left(new SyntaxError("Unexpected token ')'")));
expect(result).toEqual(E.left(new SyntaxError("Unexpected token '%'")));
});
it("should parse a function body with arguments and be able to execute it", () => {
it("should parse a function body with arguments and be able to execute it", (done) => {
const input = "return x + 1;";
const result = parseFunctionBody<[number], number>(input, "x");
pipe(
const fn = pipe(
result,
E.match(
() => fail("Expected a right"),
(result) => {
expect(result(1)).toEqual(E.right(2));
() => {
throw new Error("Expected a right");
},
(parsedFn) => {
console.log(parsedFn.toString());
return pipe(
parsedFn(1),
TE.match(
(error) => {
console.error({ error });
throw new Error("Expected a right");
},
(result) => {
console.log({ result });
return expect(result).toEqual(2);
},
),
);
},
),
);
fn().then(done, done);
});
});
57 changes: 30 additions & 27 deletions src/std/index.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,42 @@
import { pipe as p, flow as f, absurd as _absurd } from "fp-ts/function";
import {
partitionMap,
findFirst,
findFirstMap,
partition,
map as mapArr,
filter,
compact,
filter,
filterMap,
findFirst,
findFirstMap,
flatten,
map as mapArr,
partition,
partitionMap,
} from "fp-ts/Array";
import * as _O from "fp-ts/Option";
import {
Either,
ap,
bimap,
chainW,
flap,
flatMap,
fromNullable,
getOrElse,
isLeft,
isRight,
tryCatchK,
map,
getOrElse,
fromNullable,
right,
left,
map,
mapLeft,
Either,
bimap,
tryCatch,
flatMap,
ap,
flap,
chainW,
match,
right,
tryCatch,
tryCatchK,
} from "fp-ts/Either";
export type Option<T> = _O.Option<T>;
import { BaseSchema, Output, ValiError, parse as parseV } from "valibot";
import { Semigroup, concatAll } from "fp-ts/Semigroup";
import { NonEmptyArray, concatAll as concatAllNea } from "fp-ts/NonEmptyArray";
export type { NonEmptyArray } from "fp-ts/NonEmptyArray";
import * as _O from "fp-ts/Option";
import { Semigroup, concatAll } from "fp-ts/Semigroup";
import * as TE from "fp-ts/TaskEither";
import { absurd as _absurd, flow as f, pipe as p } from "fp-ts/function";
import { BaseSchema, Output, ValiError, parse as parseV } from "valibot";
export type Option<T> = _O.Option<T>;
export type { Either, Left, Right } from "fp-ts/Either";
export type { NonEmptyArray } from "fp-ts/NonEmptyArray";
export const flow = f;
export const pipe = p;
export const absurd = _absurd;
Expand Down Expand Up @@ -170,10 +171,12 @@ export function ensureError(e: unknown): Error {
return e instanceof Error ? e : new Error(String(e));
}

// There is no way to access the constructor of an async function than the prototype chain
const AsyncFunction = new Function("return async () => {}")().constructor;
/**
* Creates a function from a string that is supposed to be a function body.
* It ensures the "use strict" directive is present and returns the function.
* Because the parsing can fail, it returns an Either.
* Because the parsing can fail, it returns an TaskEither.
* The reason why the type arguments are reversed is because
* we often know what the function input types should be, but
* we can't trust the function body to return the correct type, so by default1t it will be unknown
Expand All @@ -183,8 +186,8 @@ export function parseFunctionBody<Args extends unknown[], T>(body: string, ...ar
const fnBody = `"use strict";
${body}`;
try {
const fn = new Function(...args, fnBody) as (...args: Args) => T;
return right(tryCatchK(fn, ensureError));
const fn = AsyncFunction(...args, fnBody) as (...args: Args) => Promise<T>;
return right(TE.tryCatchK(fn, ensureError));
} catch (e) {
return left(ensureError(e));
}
Expand Down
Loading