Skip to content

Commit

Permalink
add validation to API methods
Browse files Browse the repository at this point in the history
  • Loading branch information
mProjectsCode committed Sep 19, 2024
1 parent 70a8eda commit 7b75696
Show file tree
Hide file tree
Showing 17 changed files with 497 additions and 74 deletions.
Binary file modified bun.lockb
Binary file not shown.
4 changes: 4 additions & 0 deletions exampleVault/Test.md
Original file line number Diff line number Diff line change
Expand Up @@ -227,4 +227,8 @@ el.addEventListener("click", () => {

```js-engine
le)
```

```js-engine
engine.getPlugin(false)
```
11 changes: 11 additions & 0 deletions jsEngine/api/API.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ import { QueryAPI } from 'jsEngine/api/QueryAPI';
import { ReactiveComponent } from 'jsEngine/api/reactive/ReactiveComponent';
import type { JsFunc } from 'jsEngine/engine/JsExecution';
import type JsEnginePlugin from 'jsEngine/main';
import type { Validators } from 'jsEngine/utils/Validators';
import { validateAPIArgs } from 'jsEngine/utils/Validators';
import type { App, Plugin } from 'obsidian';
import { z } from 'zod';

export class API {
/**
Expand All @@ -20,6 +23,7 @@ export class API {
*/
readonly plugin: JsEnginePlugin;
readonly instanceId: InstanceId;
readonly validators: Validators;
/**
* API to interact with markdown.
*/
Expand All @@ -46,6 +50,7 @@ export class API {
this.app = app;
this.plugin = plugin;
this.instanceId = instanceId;
this.validators = plugin.validators;

this.markdown = new MarkdownAPI(this);
this.message = new MessageAPI(this);
Expand All @@ -65,6 +70,8 @@ export class API {
* @param path the vault relative path of the file to import
*/
public async importJs(path: string): Promise<unknown> {
validateAPIArgs(z.object({ path: z.string() }), { path });

let fullPath = this.app.vault.adapter.getResourcePath(path);

// we need to remove the query parameters from the path
Expand All @@ -83,6 +90,8 @@ export class API {
* @param pluginId the id of the plugin.
*/
public getPlugin(pluginId: string): Plugin | undefined {
validateAPIArgs(z.object({ pluginId: z.string() }), { pluginId });

return this.app.plugins.getPlugin(pluginId) ?? undefined;
}

Expand All @@ -94,6 +103,8 @@ export class API {
* @param initialArgs the initial arguments (for the first render) to pass to the function.
*/
public reactive(fn: JsFunc, ...initialArgs: unknown[]): ReactiveComponent {
validateAPIArgs(z.object({ fn: z.function(), initialArgs: z.array(z.unknown()) }), { fn, initialArgs });

return new ReactiveComponent(this, fn, initialArgs);
}
}
20 changes: 20 additions & 0 deletions jsEngine/api/Internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import type { API } from 'jsEngine/api/API';
import type { EngineExecutionParams } from 'jsEngine/engine/Engine';
import type { JsExecution, JsExecutionContext, JsExecutionGlobals, JsExecutionGlobalsConstructionOptions } from 'jsEngine/engine/JsExecution';
import { ResultRenderer } from 'jsEngine/engine/ResultRenderer';
import { validateAPIArgs } from 'jsEngine/utils/Validators';
import { Component, TFile } from 'obsidian';
import * as Obsidian from 'obsidian';
import { z } from 'zod';

/**
* The internal API provides access to some of js engines internals.
Expand All @@ -21,6 +23,8 @@ export class InternalAPI {
* @param params
*/
public async execute(params: EngineExecutionParams): Promise<JsExecution> {
validateAPIArgs(z.object({ params: this.apiInstance.validators.engineExecutionParams }), { params });

return await this.apiInstance.plugin.jsEngine.execute(params);
}

Expand All @@ -32,6 +36,11 @@ export class InternalAPI {
* @param component
*/
public createRenderer(container: HTMLElement, sourcePath: string, component: Component): ResultRenderer {
validateAPIArgs(
z.object({ container: this.apiInstance.validators.htmlElement, sourcePath: z.string(), component: this.apiInstance.validators.component }),
{ container, sourcePath, component },
);

return new ResultRenderer(this.apiInstance.plugin, container, sourcePath, component);
}

Expand All @@ -42,6 +51,8 @@ export class InternalAPI {
* @param params
*/
public async executeFile(path: string, params: Omit<EngineExecutionParams, 'code'>): Promise<JsExecution> {
validateAPIArgs(z.object({ path: z.string(), params: this.apiInstance.validators.engineExecutionParamsNoCode }), { path, params });

const file = this.apiInstance.app.vault.getAbstractFileByPath(path);
if (!file || !(file instanceof TFile)) {
throw new Error(`File ${path} not found.`);
Expand All @@ -60,6 +71,11 @@ export class InternalAPI {
* @param params
*/
public async executeFileSimple(path: string, params?: Omit<EngineExecutionParams, 'code' | 'component'>): Promise<JsExecution> {
validateAPIArgs(z.object({ path: z.string(), params: this.apiInstance.validators.engineExecutionParamsNoCodeAndComponent.optional() }), {
path,
params,
});

const component = new Component();
component.load();
try {
Expand All @@ -75,6 +91,8 @@ export class InternalAPI {
* @param path
*/
public async getContextForFile(path: string): Promise<JsExecutionContext> {
validateAPIArgs(z.object({ path: z.string() }), { path });

const file = this.apiInstance.app.vault.getAbstractFileByPath(path);
if (!file || !(file instanceof TFile)) {
throw new Error(`File ${path} not found.`);
Expand All @@ -95,6 +113,8 @@ export class InternalAPI {
* @param options
*/
public createExecutionGlobals(options: JsExecutionGlobalsConstructionOptions): JsExecutionGlobals {
validateAPIArgs(z.object({ options: this.apiInstance.validators.jsExecutionGlobalsConstructionOptions }), { options });

return {
app: this.apiInstance.app,
engine: options.engine ?? this.apiInstance,
Expand Down
68 changes: 54 additions & 14 deletions jsEngine/api/MarkdownAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import {
} from 'jsEngine/api/markdown/AbstractMarkdownElementContainer';
import { MarkdownBuilder } from 'jsEngine/api/markdown/MarkdownBuilder';
import { MarkdownString } from 'jsEngine/api/markdown/MarkdownString';
import { validateAPIArgs } from 'jsEngine/utils/Validators';
import { z } from 'zod';

/**
* The markdown API provides utilities for creating markdown using js.
Expand All @@ -27,7 +29,7 @@ export class MarkdownAPI {
* Creates a markdown builder.
*/
public createBuilder(): MarkdownBuilder {
return new MarkdownBuilder();
return new MarkdownBuilder(this.apiInstance);
}

/**
Expand All @@ -38,7 +40,9 @@ export class MarkdownAPI {
* @param markdown the string to wrap
*/
public create(markdown: string): MarkdownString {
return new MarkdownString(markdown);
validateAPIArgs(z.object({ markdown: z.string() }), { markdown });

return new MarkdownString(this.apiInstance, markdown);
}

/**
Expand All @@ -47,7 +51,9 @@ export class MarkdownAPI {
* @param text
*/
public createText(text: string): TextElement {
return new TextElement(text, false, false, false);
validateAPIArgs(z.object({ text: z.string() }), { text });

return new TextElement(this.apiInstance, text, false, false, false);
}

/**
Expand All @@ -56,7 +62,9 @@ export class MarkdownAPI {
* @param text
*/
public createBoldText(text: string): TextElement {
return new TextElement(text, true, false, false);
validateAPIArgs(z.object({ text: z.string() }), { text });

return new TextElement(this.apiInstance, text, true, false, false);
}

/**
Expand All @@ -65,7 +73,9 @@ export class MarkdownAPI {
* @param text
*/
public createCursiveText(text: string): TextElement {
return new TextElement(text, false, true, false);
validateAPIArgs(z.object({ text: z.string() }), { text });

return new TextElement(this.apiInstance, text, false, true, false);
}

/**
Expand All @@ -74,7 +84,9 @@ export class MarkdownAPI {
* @param text
*/
public createUnderlinedText(text: string): TextElement {
return new TextElement(text, false, false, true);
validateAPIArgs(z.object({ text: z.string() }), { text });

return new TextElement(this.apiInstance, text, false, false, true);
}

/**
Expand All @@ -83,7 +95,9 @@ export class MarkdownAPI {
* @param text
*/
public createCode(text: string): CodeElement {
return new CodeElement(text);
validateAPIArgs(z.object({ text: z.string() }), { text });

return new CodeElement(this.apiInstance, text);
}

/**
Expand All @@ -92,7 +106,9 @@ export class MarkdownAPI {
* @param content
*/
public createParagraph(content: string): ParagraphElement {
return new ParagraphElement(content);
validateAPIArgs(z.object({ content: z.string() }), { content });

return new ParagraphElement(this.apiInstance, content);
}

/**
Expand All @@ -102,14 +118,16 @@ export class MarkdownAPI {
* @param content the text of the heading
*/
public createHeading(level: number, content: string): HeadingElement {
return new HeadingElement(level, content);
validateAPIArgs(z.object({ level: z.number(), content: z.string() }), { level, content });

return new HeadingElement(this.apiInstance, level, content);
}

/**
* Creates a new markdown block quote element.
*/
public createBlockQuote(): BlockQuoteElement {
return new BlockQuoteElement();
return new BlockQuoteElement(this.apiInstance);
}

/**
Expand All @@ -120,7 +138,23 @@ export class MarkdownAPI {
* @param args the callout args, optional
*/
public createCallout(title: string, type: string, args: string = ''): CalloutElement {
return new CalloutElement(title, type, args);
validateAPIArgs(z.object({ title: z.string(), type: z.string(), args: z.string() }), { title, type, args });

return new CalloutElement(this.apiInstance, title, type, args);
}

/**
* Creates a new markdown collapsible callout element.
*
* @param title the title of the callout
* @param type the type of the callout
* @param args the callout args, optional
* @param collapsed whether the callout should be collapsed by default, optional
*/
createCollapsibleCallout(title: string, type: string, args: string = '', collapsed: boolean = false): CalloutElement {
validateAPIArgs(z.object({ title: z.string(), type: z.string(), args: z.string(), collapsed: z.boolean() }), { title, type, args, collapsed });

return new CalloutElement(this.apiInstance, title, type, args, true, collapsed);
}

/**
Expand All @@ -130,7 +164,9 @@ export class MarkdownAPI {
* @param content the content of the code block
*/
public createCodeBlock(language: string, content: string): CodeBlockElement {
return new CodeBlockElement(language, content);
validateAPIArgs(z.object({ language: z.string(), content: z.string() }), { language, content });

return new CodeBlockElement(this.apiInstance, language, content);
}

/**
Expand All @@ -140,7 +176,9 @@ export class MarkdownAPI {
* @param body the table body
*/
public createTable(header: string[], body: string[][]): TableElement {
return new TableElement(header, body);
validateAPIArgs(z.object({ header: z.array(z.string()), body: z.array(z.array(z.string())) }), { header, body });

return new TableElement(this.apiInstance, header, body);
}

/**
Expand All @@ -149,6 +187,8 @@ export class MarkdownAPI {
* @param ordered whether the list should be ordered or not (use 1. or -)
*/
createList(ordered: boolean): ListElement {
return new ListElement(ordered);
validateAPIArgs(z.object({ ordered: z.boolean() }), { ordered });

return new ListElement(this.apiInstance, ordered);
}
}
11 changes: 11 additions & 0 deletions jsEngine/api/MessageAPI.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import type { API } from 'jsEngine/api/API';
import type { MessageManager, MessageType, MessageWrapper } from 'jsEngine/messages/MessageManager';
import { Message } from 'jsEngine/messages/MessageManager';
import { validateAPIArgs } from 'jsEngine/utils/Validators';
import { z } from 'zod';

export class MessageAPI {
readonly apiInstance: API;
Expand All @@ -12,10 +14,19 @@ export class MessageAPI {
}

public createMessage(type: MessageType, title: string, content: string, code: string = ''): MessageWrapper {
validateAPIArgs(z.object({ type: this.apiInstance.validators.messageType, title: z.string(), content: z.string(), code: z.string() }), {
type,
title,
content,
code,
});

return this.messageManager.addMessage(new Message(type, title, content, code), this.apiInstance.instanceId);
}

public getMessageById(id: string): MessageWrapper | undefined {
validateAPIArgs(z.object({ id: z.string() }), { id });

return this.messageManager.messages.get().find(message => message.uuid === id);
}

Expand Down
Loading

0 comments on commit 7b75696

Please sign in to comment.