@goreal-ai/echo-pdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/ai-judge/index.d.ts +177 -0
  2. package/dist/ai-judge/index.d.ts.map +1 -0
  3. package/dist/ai-judge/index.js +299 -0
  4. package/dist/ai-judge/index.js.map +1 -0
  5. package/dist/evaluator/evaluator.d.ts +136 -0
  6. package/dist/evaluator/evaluator.d.ts.map +1 -0
  7. package/dist/evaluator/evaluator.js +407 -0
  8. package/dist/evaluator/evaluator.js.map +1 -0
  9. package/dist/evaluator/index.d.ts +7 -0
  10. package/dist/evaluator/index.d.ts.map +1 -0
  11. package/dist/evaluator/index.js +8 -0
  12. package/dist/evaluator/index.js.map +1 -0
  13. package/dist/evaluator/operators.d.ts +105 -0
  14. package/dist/evaluator/operators.d.ts.map +1 -0
  15. package/dist/evaluator/operators.js +371 -0
  16. package/dist/evaluator/operators.js.map +1 -0
  17. package/dist/index.d.ts +115 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +388 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/parser/ast.d.ts +106 -0
  22. package/dist/parser/ast.d.ts.map +1 -0
  23. package/dist/parser/ast.js +260 -0
  24. package/dist/parser/ast.js.map +1 -0
  25. package/dist/parser/index.d.ts +8 -0
  26. package/dist/parser/index.d.ts.map +1 -0
  27. package/dist/parser/index.js +13 -0
  28. package/dist/parser/index.js.map +1 -0
  29. package/dist/parser/lexer.d.ts +199 -0
  30. package/dist/parser/lexer.d.ts.map +1 -0
  31. package/dist/parser/lexer.js +491 -0
  32. package/dist/parser/lexer.js.map +1 -0
  33. package/dist/parser/parser.d.ts +49 -0
  34. package/dist/parser/parser.d.ts.map +1 -0
  35. package/dist/parser/parser.js +615 -0
  36. package/dist/parser/parser.js.map +1 -0
  37. package/dist/plugins/index.d.ts +62 -0
  38. package/dist/plugins/index.d.ts.map +1 -0
  39. package/dist/plugins/index.js +170 -0
  40. package/dist/plugins/index.js.map +1 -0
  41. package/dist/renderer/index.d.ts +6 -0
  42. package/dist/renderer/index.d.ts.map +1 -0
  43. package/dist/renderer/index.js +5 -0
  44. package/dist/renderer/index.js.map +1 -0
  45. package/dist/renderer/renderer.d.ts +97 -0
  46. package/dist/renderer/renderer.d.ts.map +1 -0
  47. package/dist/renderer/renderer.js +243 -0
  48. package/dist/renderer/renderer.js.map +1 -0
  49. package/dist/types.d.ts +255 -0
  50. package/dist/types.d.ts.map +1 -0
  51. package/dist/types.js +9 -0
  52. package/dist/types.js.map +1 -0
  53. package/package.json +54 -0
@@ -0,0 +1,62 @@
1
+ /**
2
+ * @fileoverview Plugin System - Load and manage Echo plugins
3
+ *
4
+ * This module handles loading and registering plugins for Echo.
5
+ * Plugins can add custom operators, validators, and transformations.
6
+ *
7
+ * IMPLEMENTATION GUIDE:
8
+ *
9
+ * 1. PLUGIN LOADING
10
+ * - Load from npm packages: @goreal-ai/echo-pdk-validators
11
+ * - Load from local paths: ./plugins/my-plugin.ts
12
+ * - Validate plugin structure
13
+ *
14
+ * 2. OPERATOR REGISTRATION
15
+ * - Merge plugin operators with built-ins
16
+ * - Handle conflicts (plugin can override built-in)
17
+ *
18
+ * 3. LIFECYCLE HOOKS
19
+ * - onLoad: Called when plugin is loaded
20
+ * - Future: onRender, onValidate, etc.
21
+ */
22
+ import type { EchoPlugin, OperatorDefinition } from '../types.js';
23
+ /**
24
+ * Plugin registry managing all loaded plugins.
25
+ */
26
+ export interface PluginRegistry {
27
+ /** All loaded plugins */
28
+ plugins: EchoPlugin[];
29
+ /** Merged operator definitions from all plugins */
30
+ operators: Map<string, OperatorDefinition>;
31
+ }
32
+ /**
33
+ * Create a new plugin registry.
34
+ */
35
+ export declare function createPluginRegistry(): PluginRegistry;
36
+ /**
37
+ * Load a plugin into the registry.
38
+ *
39
+ * @param registry - The plugin registry
40
+ * @param plugin - The plugin to load
41
+ */
42
+ export declare function loadPlugin(registry: PluginRegistry, plugin: EchoPlugin): Promise<void>;
43
+ /**
44
+ * Load a plugin from a path (npm package or local file).
45
+ *
46
+ * @param registry - The plugin registry
47
+ * @param path - Path to the plugin
48
+ */
49
+ export declare function loadPluginFromPath(_registry: PluginRegistry, path: string): Promise<void>;
50
+ /**
51
+ * Validate a plugin structure.
52
+ *
53
+ * @param plugin - The plugin to validate
54
+ * @throws If the plugin is invalid
55
+ */
56
+ export declare function validatePlugin(plugin: unknown): asserts plugin is EchoPlugin;
57
+ /**
58
+ * Helper function for creating plugins with type safety.
59
+ * Re-exported from main index.ts
60
+ */
61
+ export declare function definePlugin(plugin: EchoPlugin): EchoPlugin;
62
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/plugins/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAMlE;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,yBAAyB;IACzB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,mDAAmD;IACnD,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;CAC5C;AAMD;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,cAAc,CAKrD;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAC9B,QAAQ,EAAE,cAAc,EACxB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,IAAI,CAAC,CAkBf;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,cAAc,EACzB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAiBf;AAMD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,IAAI,UAAU,CAyB5E;AA+BD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,UAAU,CAI3D"}
@@ -0,0 +1,170 @@
1
+ /**
2
+ * @fileoverview Plugin System - Load and manage Echo plugins
3
+ *
4
+ * This module handles loading and registering plugins for Echo.
5
+ * Plugins can add custom operators, validators, and transformations.
6
+ *
7
+ * IMPLEMENTATION GUIDE:
8
+ *
9
+ * 1. PLUGIN LOADING
10
+ * - Load from npm packages: @goreal-ai/echo-pdk-validators
11
+ * - Load from local paths: ./plugins/my-plugin.ts
12
+ * - Validate plugin structure
13
+ *
14
+ * 2. OPERATOR REGISTRATION
15
+ * - Merge plugin operators with built-ins
16
+ * - Handle conflicts (plugin can override built-in)
17
+ *
18
+ * 3. LIFECYCLE HOOKS
19
+ * - onLoad: Called when plugin is loaded
20
+ * - Future: onRender, onValidate, etc.
21
+ */
22
+ // =============================================================================
23
+ // PLUGIN REGISTRY
24
+ // =============================================================================
25
+ /**
26
+ * Create a new plugin registry.
27
+ */
28
+ export function createPluginRegistry() {
29
+ return {
30
+ plugins: [],
31
+ operators: new Map(),
32
+ };
33
+ }
34
+ /**
35
+ * Load a plugin into the registry.
36
+ *
37
+ * @param registry - The plugin registry
38
+ * @param plugin - The plugin to load
39
+ */
40
+ export async function loadPlugin(registry, plugin) {
41
+ // Validate plugin structure
42
+ validatePlugin(plugin);
43
+ // Register operators
44
+ if (plugin.operators) {
45
+ for (const [name, definition] of Object.entries(plugin.operators)) {
46
+ registry.operators.set(name, definition);
47
+ }
48
+ }
49
+ // Call onLoad hook
50
+ if (plugin.onLoad) {
51
+ await plugin.onLoad();
52
+ }
53
+ // Add to registry
54
+ registry.plugins.push(plugin);
55
+ }
56
+ /**
57
+ * Load a plugin from a path (npm package or local file).
58
+ *
59
+ * @param registry - The plugin registry
60
+ * @param path - Path to the plugin
61
+ */
62
+ export async function loadPluginFromPath(_registry, path) {
63
+ // TODO: Implement plugin loading from path
64
+ //
65
+ // IMPLEMENTATION:
66
+ //
67
+ // 1. DETERMINE PATH TYPE
68
+ // - If starts with @, ., or / -> resolve as module path
69
+ // - Otherwise -> resolve as npm package
70
+ //
71
+ // 2. DYNAMIC IMPORT
72
+ // const module = await import(resolvedPath);
73
+ // const plugin = module.default;
74
+ //
75
+ // 3. LOAD PLUGIN
76
+ // await loadPlugin(registry, plugin);
77
+ throw new Error(`Plugin loading not implemented: ${path}`);
78
+ }
79
+ // =============================================================================
80
+ // VALIDATION
81
+ // =============================================================================
82
+ /**
83
+ * Validate a plugin structure.
84
+ *
85
+ * @param plugin - The plugin to validate
86
+ * @throws If the plugin is invalid
87
+ */
88
+ export function validatePlugin(plugin) {
89
+ if (!plugin || typeof plugin !== 'object') {
90
+ throw new Error('Plugin must be an object');
91
+ }
92
+ const p = plugin;
93
+ if (typeof p.name !== 'string' || p.name.length === 0) {
94
+ throw new Error('Plugin must have a name');
95
+ }
96
+ if (typeof p.version !== 'string') {
97
+ throw new Error('Plugin must have a version');
98
+ }
99
+ if (p.operators !== undefined) {
100
+ if (typeof p.operators !== 'object') {
101
+ throw new Error('Plugin operators must be an object');
102
+ }
103
+ // Validate each operator
104
+ for (const [name, def] of Object.entries(p.operators)) {
105
+ validateOperatorDefinition(name, def);
106
+ }
107
+ }
108
+ }
109
+ /**
110
+ * Validate an operator definition.
111
+ */
112
+ function validateOperatorDefinition(name, def) {
113
+ if (!def || typeof def !== 'object') {
114
+ throw new Error(`Operator ${name} must be an object`);
115
+ }
116
+ const d = def;
117
+ if (!['comparison', 'unary', 'ai'].includes(d.type)) {
118
+ throw new Error(`Operator ${name} must have type: comparison, unary, or ai`);
119
+ }
120
+ if (typeof d.handler !== 'function') {
121
+ throw new Error(`Operator ${name} must have a handler function`);
122
+ }
123
+ if (typeof d.description !== 'string') {
124
+ throw new Error(`Operator ${name} must have a description`);
125
+ }
126
+ }
127
+ // =============================================================================
128
+ // PLUGIN CREATION HELPER
129
+ // =============================================================================
130
+ /**
131
+ * Helper function for creating plugins with type safety.
132
+ * Re-exported from main index.ts
133
+ */
134
+ export function definePlugin(plugin) {
135
+ // Validate at definition time
136
+ validatePlugin(plugin);
137
+ return plugin;
138
+ }
139
+ // =============================================================================
140
+ // IMPLEMENTATION NOTES
141
+ // =============================================================================
142
+ /*
143
+ NEXT STEPS TO IMPLEMENT:
144
+
145
+ 1. PATH RESOLUTION
146
+ - Handle npm packages (@goreal-ai/echo-pdk-foo)
147
+ - Handle relative paths (./foo)
148
+ - Handle absolute paths (/path/to/foo)
149
+
150
+ 2. HOT RELOADING (FUTURE)
151
+ For development mode, support reloading plugins without restart.
152
+
153
+ 3. PLUGIN DISCOVERY
154
+ - Scan node_modules for echo-pdk plugins
155
+ - Read from echo.config.yaml
156
+
157
+ 4. LIFECYCLE HOOKS
158
+ Add more hooks:
159
+ - onValidate: Custom validation rules
160
+ - onBeforeRender: Transform AST before render
161
+ - onAfterRender: Transform output after render
162
+
163
+ 5. TESTS
164
+ Create plugins.test.ts with tests for:
165
+ - Plugin validation
166
+ - Operator registration
167
+ - Path loading
168
+ - Lifecycle hooks
169
+ */
170
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/plugins/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @fileoverview Renderer module exports
3
+ */
4
+ export { render, renderTemplate } from './renderer.js';
5
+ export type { RenderOptions } from './renderer.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/renderer/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACvD,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * @fileoverview Renderer module exports
3
+ */
4
+ export { render, renderTemplate } from './renderer.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/renderer/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * @fileoverview Echo Renderer - AST to text output
3
+ *
4
+ * This file implements the renderer for Echo DSL.
5
+ * The renderer traverses the evaluated AST and produces the final text output.
6
+ *
7
+ * By the time the renderer runs:
8
+ * 1. All conditions have been evaluated
9
+ * 2. Only the nodes that should be rendered are in the AST
10
+ * 3. AI judges have been resolved
11
+ *
12
+ * The renderer's job is to:
13
+ * 1. Walk the AST
14
+ * 2. For text nodes: output the text as-is
15
+ * 3. For variable nodes: substitute the value from context
16
+ * 4. Preserve whitespace (prompts are whitespace-sensitive)
17
+ */
18
+ import type { ASTNode, EchoConfig, OperatorDefinition } from '../types.js';
19
+ /**
20
+ * Options for the renderer.
21
+ */
22
+ export interface RenderOptions {
23
+ /** Variable context */
24
+ context: Record<string, unknown>;
25
+ /** Echo configuration */
26
+ config?: EchoConfig;
27
+ /** Trim leading/trailing whitespace from output */
28
+ trim?: boolean;
29
+ /** Collapse multiple newlines into one */
30
+ collapseNewlines?: boolean;
31
+ }
32
+ /**
33
+ * Render an evaluated AST to a string.
34
+ *
35
+ * @param ast - The evaluated AST nodes
36
+ * @param options - Render options
37
+ * @returns The rendered string
38
+ *
39
+ * @example
40
+ * ```typescript
41
+ * const output = render(evaluatedAst, {
42
+ * context: { name: 'Alice' },
43
+ * trim: true,
44
+ * });
45
+ * ```
46
+ */
47
+ export declare function render(ast: ASTNode[], options: RenderOptions): string;
48
+ /**
49
+ * Full render pipeline: parse -> evaluate -> render.
50
+ *
51
+ * This is the main entry point for rendering a template.
52
+ *
53
+ * @param template - The Echo template string
54
+ * @param context - Variable context
55
+ * @param config - Echo configuration
56
+ * @param operators - Custom operators from plugins
57
+ * @returns The rendered string
58
+ *
59
+ * @example
60
+ * ```typescript
61
+ * const output = await renderTemplate(
62
+ * 'Hello {{name}}!',
63
+ * { name: 'Alice' }
64
+ * );
65
+ * // Output: "Hello Alice!"
66
+ * ```
67
+ *
68
+ * @example
69
+ * ```typescript
70
+ * const template = `
71
+ * [#IF {{tier}} #equals(premium)]
72
+ * Welcome, premium user!
73
+ * [ELSE]
74
+ * Upgrade to premium for more features.
75
+ * [END IF]
76
+ * `;
77
+ *
78
+ * const output = await renderTemplate(template, { tier: 'premium' });
79
+ * // Output: " Welcome, premium user!\n"
80
+ * ```
81
+ */
82
+ export declare function renderTemplate(template: string, context: Record<string, unknown>, config?: EchoConfig, operators?: Map<string, OperatorDefinition>): Promise<string>;
83
+ /**
84
+ * Format errors with source context for display.
85
+ *
86
+ * @param template - The original template
87
+ * @param errors - Parse or evaluation errors
88
+ * @returns Formatted error string
89
+ */
90
+ export declare function formatErrors(template: string, errors: {
91
+ message: string;
92
+ location?: {
93
+ startLine: number;
94
+ startColumn: number;
95
+ };
96
+ }[]): string;
97
+ //# sourceMappingURL=renderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/renderer/renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EACV,OAAO,EAGP,UAAU,EACV,kBAAkB,EACnB,MAAM,aAAa,CAAC;AAQrB;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,uBAAuB;IACvB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,yBAAyB;IACzB,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,mDAAmD;IACnD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,0CAA0C;IAC1C,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAMD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,aAAa,GAAG,MAAM,CAsBrE;AAiID;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAsB,cAAc,CAClC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,MAAM,GAAE,UAAe,EACvB,SAAS,GAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAa,GACrD,OAAO,CAAC,MAAM,CAAC,CAwBjB;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,EAAE,GACnF,MAAM,CAwBR"}
@@ -0,0 +1,243 @@
1
+ /**
2
+ * @fileoverview Echo Renderer - AST to text output
3
+ *
4
+ * This file implements the renderer for Echo DSL.
5
+ * The renderer traverses the evaluated AST and produces the final text output.
6
+ *
7
+ * By the time the renderer runs:
8
+ * 1. All conditions have been evaluated
9
+ * 2. Only the nodes that should be rendered are in the AST
10
+ * 3. AI judges have been resolved
11
+ *
12
+ * The renderer's job is to:
13
+ * 1. Walk the AST
14
+ * 2. For text nodes: output the text as-is
15
+ * 3. For variable nodes: substitute the value from context
16
+ * 4. Preserve whitespace (prompts are whitespace-sensitive)
17
+ */
18
+ import { parse } from '../parser/parser.js';
19
+ import { evaluate, resolveVariable } from '../evaluator/evaluator.js';
20
+ // =============================================================================
21
+ // RENDERER
22
+ // =============================================================================
23
+ /**
24
+ * Render an evaluated AST to a string.
25
+ *
26
+ * @param ast - The evaluated AST nodes
27
+ * @param options - Render options
28
+ * @returns The rendered string
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * const output = render(evaluatedAst, {
33
+ * context: { name: 'Alice' },
34
+ * trim: true,
35
+ * });
36
+ * ```
37
+ */
38
+ export function render(ast, options) {
39
+ const parts = [];
40
+ for (const node of ast) {
41
+ const rendered = renderNode(node, options);
42
+ if (rendered !== undefined) {
43
+ parts.push(rendered);
44
+ }
45
+ }
46
+ let result = parts.join('');
47
+ // Apply post-processing
48
+ if (options.collapseNewlines) {
49
+ result = collapseNewlines(result);
50
+ }
51
+ if (options.trim) {
52
+ result = result.trim();
53
+ }
54
+ return result;
55
+ }
56
+ /**
57
+ * Render a single AST node.
58
+ *
59
+ * @param node - The node to render
60
+ * @param options - Render options
61
+ * @returns The rendered string or undefined if nothing to render
62
+ */
63
+ function renderNode(node, options) {
64
+ switch (node.type) {
65
+ case 'text':
66
+ return renderText(node);
67
+ case 'variable':
68
+ return renderVariable(node, options);
69
+ case 'conditional':
70
+ // By the time we render, conditionals should have been evaluated
71
+ // This shouldn't happen, but handle gracefully
72
+ return render(node.consequent, options);
73
+ case 'section':
74
+ // Section definitions are not rendered inline
75
+ // They're stored for [#INCLUDE] references
76
+ return undefined;
77
+ case 'import':
78
+ // Imports should be resolved before rendering
79
+ // If we see one here, it means it wasn't resolved
80
+ if (options.config?.strict) {
81
+ throw new Error(`Unresolved import: ${node.path}`);
82
+ }
83
+ return undefined;
84
+ case 'include':
85
+ // Includes should be resolved before rendering
86
+ if (options.config?.strict) {
87
+ throw new Error(`Unresolved include: ${node.name}`);
88
+ }
89
+ return undefined;
90
+ default: {
91
+ // Exhaustiveness check
92
+ const _exhaustive = node;
93
+ throw new Error(`Unknown node type: ${_exhaustive.type}`);
94
+ }
95
+ }
96
+ }
97
+ /**
98
+ * Render a text node.
99
+ */
100
+ function renderText(node) {
101
+ return node.value;
102
+ }
103
+ /**
104
+ * Render a variable node.
105
+ *
106
+ * @param node - The variable node
107
+ * @param options - Render options
108
+ * @returns The variable value as string
109
+ */
110
+ function renderVariable(node, options) {
111
+ const value = resolveVariable(node.path, options.context, {
112
+ strict: options.config?.strict,
113
+ });
114
+ // Handle undefined
115
+ if (value === undefined || value === null) {
116
+ // Use default value if provided
117
+ if (node.defaultValue !== undefined) {
118
+ return node.defaultValue;
119
+ }
120
+ // In strict mode, throw
121
+ if (options.config?.strict) {
122
+ throw new Error(`Undefined variable: ${node.path}`);
123
+ }
124
+ // Lenient mode: render empty string
125
+ return '';
126
+ }
127
+ // Convert to string
128
+ return stringify(value);
129
+ }
130
+ /**
131
+ * Convert a value to string for rendering.
132
+ *
133
+ * @param value - The value to stringify
134
+ * @returns String representation
135
+ */
136
+ function stringify(value) {
137
+ if (typeof value === 'string') {
138
+ return value;
139
+ }
140
+ if (typeof value === 'number' || typeof value === 'boolean') {
141
+ return String(value);
142
+ }
143
+ if (Array.isArray(value)) {
144
+ return value.map(stringify).join(', ');
145
+ }
146
+ if (typeof value === 'object' && value !== null) {
147
+ return JSON.stringify(value);
148
+ }
149
+ return String(value);
150
+ }
151
+ // =============================================================================
152
+ // POST-PROCESSING
153
+ // =============================================================================
154
+ /**
155
+ * Collapse multiple consecutive newlines into a maximum of two.
156
+ *
157
+ * This is useful for cleaning up output when conditionals
158
+ * leave empty lines.
159
+ */
160
+ function collapseNewlines(text) {
161
+ return text.replace(/\n{3,}/g, '\n\n');
162
+ }
163
+ // =============================================================================
164
+ // FULL RENDER PIPELINE
165
+ // =============================================================================
166
+ /**
167
+ * Full render pipeline: parse -> evaluate -> render.
168
+ *
169
+ * This is the main entry point for rendering a template.
170
+ *
171
+ * @param template - The Echo template string
172
+ * @param context - Variable context
173
+ * @param config - Echo configuration
174
+ * @param operators - Custom operators from plugins
175
+ * @returns The rendered string
176
+ *
177
+ * @example
178
+ * ```typescript
179
+ * const output = await renderTemplate(
180
+ * 'Hello {{name}}!',
181
+ * { name: 'Alice' }
182
+ * );
183
+ * // Output: "Hello Alice!"
184
+ * ```
185
+ *
186
+ * @example
187
+ * ```typescript
188
+ * const template = `
189
+ * [#IF {{tier}} #equals(premium)]
190
+ * Welcome, premium user!
191
+ * [ELSE]
192
+ * Upgrade to premium for more features.
193
+ * [END IF]
194
+ * `;
195
+ *
196
+ * const output = await renderTemplate(template, { tier: 'premium' });
197
+ * // Output: " Welcome, premium user!\n"
198
+ * ```
199
+ */
200
+ export async function renderTemplate(template, context, config = {}, operators = new Map()) {
201
+ // Step 1: Parse the template to AST
202
+ const parseResult = parse(template);
203
+ if (!parseResult.success || !parseResult.ast) {
204
+ const formattedErrors = formatErrors(template, parseResult.errors);
205
+ throw new Error(`Parse error:\n${formattedErrors}`);
206
+ }
207
+ // Step 2: Evaluate the AST
208
+ const { ast: evaluatedAst } = await evaluate(parseResult.ast, context, config, operators);
209
+ // Step 3: Render the evaluated AST
210
+ return render(evaluatedAst, {
211
+ context,
212
+ config,
213
+ trim: false, // Preserve whitespace by default
214
+ collapseNewlines: true, // Clean up empty lines from conditionals
215
+ });
216
+ }
217
+ /**
218
+ * Format errors with source context for display.
219
+ *
220
+ * @param template - The original template
221
+ * @param errors - Parse or evaluation errors
222
+ * @returns Formatted error string
223
+ */
224
+ export function formatErrors(template, errors) {
225
+ const lines = template.split('\n');
226
+ const formatted = [];
227
+ for (const error of errors) {
228
+ formatted.push(`Error: ${error.message}`);
229
+ if (error.location) {
230
+ const { startLine, startColumn } = error.location;
231
+ const lineIndex = startLine - 1;
232
+ if (lineIndex >= 0 && lineIndex < lines.length) {
233
+ const sourceLine = lines[lineIndex];
234
+ const pointer = ' '.repeat(startColumn - 1) + '^';
235
+ formatted.push(` ${startLine} | ${sourceLine}`);
236
+ formatted.push(` | ${pointer}`);
237
+ }
238
+ }
239
+ formatted.push('');
240
+ }
241
+ return formatted.join('\n');
242
+ }
243
+ //# sourceMappingURL=renderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderer.js","sourceRoot":"","sources":["../../src/renderer/renderer.ts"],"names":[],"mappings":"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"}