Add Python macro worker runtime, ScriptEngine resolution, and PageRenderer/registry integration

Co-authored-by: rfc1437 <774975+rfc1437@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-02-26 21:41:26 +00:00
parent dd5a2e3377
commit b34cb4a110
8 changed files with 679 additions and 23 deletions

View File

@@ -24,6 +24,9 @@ export type {
MacroParams,
MacroRenderContext,
ParsedMacro,
PythonMacroInfo,
PythonMacroResolver,
PythonMacroRendererFn,
} from './types';
// Re-export registry functions
@@ -39,4 +42,5 @@ export {
renderMacro,
renderAllMacros,
getEditorPreview,
setPythonMacroResolver,
} from './registry';

View File

@@ -5,11 +5,22 @@
* Macros self-register using registerMacro() function.
*/
import type { MacroDefinition, MacroParams, MacroRenderContext, ParsedMacro } from './types';
import type {
MacroDefinition,
MacroParams,
MacroRenderContext,
ParsedMacro,
PythonMacroResolver,
PythonMacroRendererFn,
} from './types';
// Internal registry storage
const macroRegistry = new Map<string, MacroDefinition>();
// Python macro resolution
let pythonMacroResolverFn: PythonMacroResolver | null = null;
let pythonMacroRendererFn: PythonMacroRendererFn | null = null;
/**
* Register a macro definition.
* Call this from each macro definition file.
@@ -25,6 +36,18 @@ export function registerMacro(macro: MacroDefinition): void {
macroRegistry.set(name, macro);
}
/**
* Set the Python macro resolver and renderer for preview rendering.
* When a macro is not found in the JS registry, the resolver will be called.
*/
export function setPythonMacroResolver(
resolver: PythonMacroResolver | null,
renderer: PythonMacroRendererFn | null,
): void {
pythonMacroResolverFn = resolver;
pythonMacroRendererFn = renderer;
}
/**
* Get a macro definition by name.
*
@@ -124,6 +147,7 @@ export function parseMacros(markdown: string): ParsedMacro[] {
/**
* Render a single macro to HTML.
* First checks JS registry, then falls back to Python macro resolver.
*
* @param macro - The parsed macro
* @param context - Render context
@@ -135,25 +159,36 @@ export async function renderMacro(
): Promise<string> {
const definition = getMacro(macro.name);
if (!definition) {
return `<span class="macro-error" title="Unknown macro: ${macro.name}">${macro.rawText}</span>`;
}
// Validate if validator exists
if (definition.validate) {
const error = definition.validate(macro.params);
if (error) {
return `<span class="macro-error" title="${error}">${macro.rawText}</span>`;
if (definition) {
// Validate if validator exists
if (definition.validate) {
const error = definition.validate(macro.params);
if (error) {
return `<span class="macro-error" title="${error}">${macro.rawText}</span>`;
}
}
try {
const result = definition.render(macro.params, context);
return result instanceof Promise ? await result : result;
} catch (error) {
const message = error instanceof Error ? error.message : 'Render error';
return `<span class="macro-error" title="${message}">${macro.rawText}</span>`;
}
}
try {
const result = definition.render(macro.params, context);
return result instanceof Promise ? await result : result;
} catch (error) {
const message = error instanceof Error ? error.message : 'Render error';
return `<span class="macro-error" title="${message}">${macro.rawText}</span>`;
if (pythonMacroResolverFn && pythonMacroRendererFn) {
try {
const pythonInfo = await pythonMacroResolverFn(macro.name);
if (pythonInfo) {
return await pythonMacroRendererFn(pythonInfo, macro.params, context);
}
} catch {
return `<span class="macro-error" title="Python macro error">${macro.rawText}</span>`;
}
}
return `<span class="macro-error" title="Unknown macro: ${macro.name}">${macro.rawText}</span>`;
}
/**

View File

@@ -75,3 +75,30 @@ export interface ParsedMacro {
/** End position in the source text */
end: number;
}
/**
* Resolved Python macro script information for rendering.
*/
export interface PythonMacroInfo {
scriptId: string;
slug: string;
code: string;
entrypoint: string;
version: number;
}
/**
* Resolver function that checks if a macro name maps to a Python script.
* Returns script info if found, null otherwise.
*/
export type PythonMacroResolver = (macroName: string) => Promise<PythonMacroInfo | null>;
/**
* Renderer function that executes a Python macro with the given context.
* Returns the rendered HTML string.
*/
export type PythonMacroRendererFn = (
info: PythonMacroInfo,
params: MacroParams,
context: MacroRenderContext,
) => Promise<string>;