Skip to content

Commit

Permalink
Merge pull request #102 from danielo515/feat-imporve-result-helpers
Browse files Browse the repository at this point in the history
feat - pick and omit in result helper methods
  • Loading branch information
danielo515 authored Oct 26, 2023
2 parents 41790ff + b5d29ce commit 068a49c
Show file tree
Hide file tree
Showing 12 changed files with 347 additions and 28 deletions.
23 changes: 20 additions & 3 deletions package-lock.json

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

8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"build": "npm run check && node esbuild.config.mjs production",
"check": "svelte-check --tsconfig tsconfig.json",
"test": "jest",
"test-w": "jest --watch",
"test-w": "jest --watch --no-cache",
"version": "node version-bump.mjs && git add manifest.json versions.json"
},
"keywords": [],
Expand All @@ -20,6 +20,7 @@
"@types/node": "^16.11.6",
"@typescript-eslint/eslint-plugin": "^6.7.0",
"@typescript-eslint/parser": "^6.7.0",
"@unsplash/ts-namespace-import-plugin": "^1.0.0",
"builtin-modules": "3.3.0",
"esbuild": "0.17.3",
"esbuild-svelte": "^0.8.0",
Expand All @@ -31,11 +32,12 @@
"ts-jest": "^29.1.1",
"ts-node": "^10.9.1",
"tslib": "2.4.0",
"typescript": "^5.2.2"
"typescript": "^5.2.2",
"yaml": "^2.3.3"
},
"dependencies": {
"fp-ts": "^2.16.1",
"fuse.js": "^6.6.2",
"valibot": "^0.19.0"
}
}
}
8 changes: 4 additions & 4 deletions src/API.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { App } from "obsidian";

import { MigrationError, type FormDefinition, type FormOptions } from "./core/formDefinition";
import FormResult from "./FormResult";
import FormResult from "./core/FormResult";
import { exampleModalDefinition } from "./exampleModalDefinition";
import ModalFormPlugin from "./main";
import { ModalFormError } from "./utils/Error";
Expand Down Expand Up @@ -49,9 +49,9 @@ export class API {
getFormByName(name: string): FormDefinition | undefined {
const form = this.plugin.settings?.formDefinitions.find((form) => form.name === name);
if (form instanceof MigrationError) {
log_notice('🚫 The form you tried to load has an invalid format',
`The form "${name}" has an invalid format.`+
`We tried to automatically convert it but it failed, please fix it manually in the forms manager.
log_notice('🚫 The form you tried to load has an invalid format',
`The form "${name}" has an invalid format.` +
`We tried to automatically convert it but it failed, please fix it manually in the forms manager.
`)
return undefined;
} else {
Expand Down
10 changes: 5 additions & 5 deletions src/FormModal.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { App, Modal, Platform, Setting } from "obsidian";
import MultiSelect from "./views/components/MultiSelect.svelte";
import FormResult, { formDataFromFormOptions, type ModalFormData } from "./FormResult";
import FormResult, { formDataFromFormOptions, type ModalFormData } from "./core/FormResult";
import { exhaustiveGuard } from "./safety";
import { get_tfiles_from_folder } from "./utils/files";
import type { FormDefinition, FormOptions } from "./core/formDefinition";
Expand Down Expand Up @@ -39,7 +39,7 @@ export class FormModal extends Modal {
fieldBase.setClass('modal-form-textarea')
return fieldBase.addTextArea((textEl) => {
if (typeof initialValue === 'string') { textEl.setValue(initialValue); }
textEl.onChange(value => {
textEl.onChange((value) => {
this.formResult[definition.name] = value;
});
textEl.inputEl.rows = 6;
Expand Down Expand Up @@ -133,7 +133,7 @@ export class FormModal extends Modal {
this.formResult[definition.name] = this.formResult[definition.name] || []
const options = fieldInput.source == 'fixed'
? fieldInput.multi_select_options
: get_tfiles_from_folder(fieldInput.folder, this.app).map(file => file.basename);
: get_tfiles_from_folder(fieldInput.folder, this.app).map((file) => file.basename);
this.svelteComponents.push(new MultiSelect({
target: fieldBase.controlEl,
props: {
Expand Down Expand Up @@ -205,7 +205,7 @@ export class FormModal extends Modal {
return exhaustiveGuard(type);
}
});

const submit = () => {
this.onSubmit(new FormResult(this.formResult, "ok"));
this.close();
Expand All @@ -230,7 +230,7 @@ export class FormModal extends Modal {

onClose() {
const { contentEl } = this;
this.svelteComponents.forEach(component => component.$destroy())
this.svelteComponents.forEach((component) => component.$destroy())
contentEl.empty();
this.formResult = {};
}
Expand Down
156 changes: 156 additions & 0 deletions src/core/FormResult.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
jest.mock("obsidian");
import FormResult, { ModalFormData } from "./FormResult";

describe("FormResult", () => {
const formData: ModalFormData = {
name: "John Doe",
age: 30,
hobbies: ["reading", "swimming"],
isEmployed: true,
};

describe("constructor", () => {
it("should create a new FormResult instance with the provided data and status", () => {
const result = new FormResult(formData, "ok");
expect(result).toBeInstanceOf(FormResult);
expect(result.getData()).toEqual(formData);
expect(result.status).toEqual("ok");
});
});

describe("asFrontmatterString", () => {
it("should return the data as a YAML frontmatter string", () => {
const result = new FormResult(formData, "ok");
const expectedOutput = `name: John Doe
age: 30
hobbies:
- reading
- swimming
isEmployed: true
`;
expect(result.asFrontmatterString()).toEqual(expectedOutput);
});
});

describe("asDataviewProperties", () => {
it("should return the data as a string of dataview properties", () => {
const result = new FormResult(formData, "ok");
const expectedOutput = `name:: John Doe
age:: 30
hobbies:: "reading","swimming"
isEmployed:: true`;
expect(result.asDataviewProperties()).toEqual(expectedOutput);
});
});

describe("getData", () => {
it("should return a copy of the data contained in the FormResult instance", () => {
const result = new FormResult(formData, "ok");
const dataCopy = result.getData();
expect(dataCopy).toEqual(formData);
expect(dataCopy).not.toBe(formData);
});
});

describe("asString", () => {
it("should return the data formatted as a string matching the provided template", () => {
const result = new FormResult(formData, "ok");
const template = "My name is {{name}}, and I am {{age}} years old.";
const expectedOutput =
"My name is John Doe, and I am 30 years old.";
expect(result.asString(template)).toEqual(expectedOutput);
});
});
describe("asDataviewProperties pick/omit", () => {
it("should return the data as a string of dataview properties with only the specified keys using options.pick", () => {
const result = new FormResult(formData, "ok");
const expectedOutput = `name:: John Doe
age:: 30`;
expect(
result.asDataviewProperties({ pick: ["name", "age"] })
).toEqual(expectedOutput);
});

it("should return the data as a string of dataview properties with all keys except the specified ones using options.omit", () => {
const result = new FormResult(formData, "ok");
const expectedOutput = `name:: John Doe
age:: 30`;
expect(
result.asDataviewProperties({ omit: ["hobbies", "isEmployed"] })
).toEqual(expectedOutput);
});

it("should return the data as a string of dataview properties with only the specified keys using options.pick and ignoring options.omit", () => {
const result = new FormResult(formData, "ok");
const expectedOutput = `name:: John Doe
age:: 30`;
expect(
result.asDataviewProperties({
pick: ["name", "age"],
omit: ["hobbies", "isEmployed"],
})
).toEqual(expectedOutput);
});

it("should return the data as a string of dataview properties with all keys except the specified ones using options.omit and ignoring options.pick", () => {
const result = new FormResult(formData, "ok");
const expectedOutput = `name:: John Doe
age:: 30`;
expect(
result.asDataviewProperties({
omit: ["hobbies", "isEmployed"],
pick: ["name", "age"],
})
).toEqual(expectedOutput);
});
});
describe("asFrontmatterString pick/omit", () => {
it("should return the data as a YAML frontmatter string with only the specified keys using options.pick", () => {
const result = new FormResult(formData, "ok");
const expectedOutput = `name: John Doe
age: 30`;
expect(
result.asFrontmatterString({ pick: ["name", "age"] }).trim()
).toEqual(expectedOutput);
});

it("should return the data as a YAML frontmatter string with all keys except the specified ones using options.omit", () => {
const result = new FormResult(formData, "ok");
const expectedOutput = `name: John Doe
age: 30`;
expect(
result
.asFrontmatterString({ omit: ["hobbies", "isEmployed"] })
.trim()
).toEqual(expectedOutput);
});

it("should return the data as a YAML frontmatter string with only the specified keys using options.pick and ignoring options.omit", () => {
const result = new FormResult(formData, "ok");
const expectedOutput = `name: John Doe
age: 30`;
expect(
result
.asFrontmatterString({
pick: ["name", "age"],
omit: ["hobbies", "isEmployed"],
})
.trim()
).toEqual(expectedOutput);
});

it("should return the data as a YAML frontmatter string with all keys except the specified ones using options.omit and ignoring options.pick", () => {
const result = new FormResult(formData, "ok");
const expectedOutput = `name: John Doe
age: 30`;
expect(
result
.asFrontmatterString({
omit: ["hobbies", "isEmployed"],
pick: ["name", "age"],
})
.trim()
).toEqual(expectedOutput);
});
});
});
33 changes: 26 additions & 7 deletions src/FormResult.ts → src/core/FormResult.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { objectSelect } from './objectSelect';
import { stringifyYaml } from "obsidian";
import { log_error } from "./utils/Log";
import { ModalFormError } from "./utils/Error";
import { log_error } from "../utils/Log";
import { ModalFormError } from "../utils/Error";

type ResultStatus = "ok" | "cancelled";

Expand All @@ -15,6 +16,7 @@ function isPrimitiveArray(value: unknown): value is string[] {
return Array.isArray(value) && value.every(isPrimitive)
}


export function formDataFromFormOptions(values: Record<string, unknown>) {
const result: ModalFormData = {};
const invalidKeys = []
Expand All @@ -35,16 +37,33 @@ export function formDataFromFormOptions(values: Record<string, unknown>) {

export default class FormResult {
constructor(private data: ModalFormData, public status: ResultStatus) { }
asFrontmatterString() {
return stringifyYaml(this.data);
/**
* Transform the current data into a frontmatter string, which is expected
* to be enclosed in `---` when used in a markdown file.
* This method does not add the enclosing `---` to the string,
* so you can put it anywhere inside the frontmatter.
* @param {Object} [options] an options object describing what options to pick or omit
* @param {string[]} [options.pick] an array of key names to pick from the data
* @param {string[]} [options.omit] an array of key names to omit from the data
* @returns the data formatted as a frontmatter string
*/
asFrontmatterString(options?: unknown) {
const data = objectSelect(this.data, options)
return stringifyYaml(data);
}
/**
* Return the current data as a block of dataview properties
* @param {Object} [options] an options object describing what options to pick or omit
* @param {string[]} [options.pick] an array of key names to pick from the data
* @param {string[]} [options.omit] an array of key names to omit from the data
* @returns string
*/
asDataviewProperties(): string {
return Object.entries(this.data)
.map(([key, value]) => `${key}:: ${value}`)
asDataviewProperties(options?: unknown): string {
const data = objectSelect(this.data, options)
return Object.entries(data)
.map(([key, value]) =>
`${key}:: ${Array.isArray(value) ? value.map((v) => JSON.stringify(v)) : value}`
)
.join("\n");
}
/**
Expand Down
4 changes: 4 additions & 0 deletions src/core/__mocks__/obsidian.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { stringify } from 'yaml'
export function stringifyYaml(data: unknown) {
return stringify(data)
}
Loading

0 comments on commit 068a49c

Please sign in to comment.