Files
plainleaf/common/space_script.ts
T
2025-03-21 16:12:10 +01:00

105 lines
2.7 KiB
TypeScript

import type { ParseTree } from "../plug-api/lib/tree.ts";
import type { AppCommand, CommandDef, SlashCommand } from "$lib/command.ts";
import { Intl, Temporal, toTemporalInstant } from "@js-temporal/polyfill";
import type { SlashCommandDef } from "$lib/manifest.ts";
// @ts-ignore: Temporal polyfill
Date.prototype.toTemporalInstant = toTemporalInstant;
// @ts-ignore: Temporal polyfill
globalThis.Temporal = Temporal;
// @ts-ignore: Intl polyfill
Object.apply(globalThis.Intl, Intl);
type FunctionDef = {
name: string;
};
type AttributeExtractorDef = {
tags: string[];
};
export type EventListenerDef = {
name: string;
};
type AttributeExtractorCallback = (
text: string,
tree: ParseTree,
) => Record<string, any> | null | Promise<Record<string, any> | null>;
export class ScriptEnvironment {
functions: Record<string, (...args: any[]) => any> = {};
commands: Record<string, AppCommand> = {};
slashCommands: Record<string, SlashCommand> = {};
attributeExtractors: Record<string, AttributeExtractorCallback[]> = {};
eventHandlers: Record<string, ((...args: any[]) => any)[]> = {};
// Public API
// Register function
registerFunction(def: FunctionDef, fn: (...args: any[]) => any): void;
// Legacy invocation
registerFunction(name: string, fn: (...args: any[]) => any): void;
registerFunction(
arg: string | FunctionDef,
fn: (...args: any[]) => any,
): void {
if (typeof arg === "string") {
console.warn(
"registerFunction with string is deprecated, use `{name: string}` instead",
);
arg = { name: arg };
}
if (this.functions[arg.name]) {
console.warn(`Function ${arg.name} already registered, overwriting`);
}
this.functions[arg.name] = fn;
}
registerCommand(command: CommandDef, fn: (...args: any[]) => any) {
this.commands[command.name] = {
command,
run: (...args: any[]) => {
return new Promise((resolve) => {
// Next tick
setTimeout(() => {
resolve(fn(...args));
});
});
},
};
}
registerSlashCommand(
def: SlashCommandDef,
fn: (...args: any[]) => any,
) {
this.slashCommands[def.name] = {
slashCommand: def,
run: fn,
};
}
registerAttributeExtractor(
def: AttributeExtractorDef,
callback: AttributeExtractorCallback,
) {
for (const tag of def.tags) {
if (!this.attributeExtractors[tag]) {
this.attributeExtractors[tag] = [];
}
this.attributeExtractors[tag].push(callback);
}
}
registerEventListener(
def: EventListenerDef,
callback: (...args: any[]) => any,
) {
if (!this.eventHandlers[def.name]) {
this.eventHandlers[def.name] = [];
}
this.eventHandlers[def.name].push(callback);
}
}