@marktoflow/core 2.0.0-alpha.12 → 2.0.0-alpha.13
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.
- package/README.md +147 -4
- package/dist/built-in-operations.d.ts +140 -0
- package/dist/built-in-operations.d.ts.map +1 -0
- package/dist/built-in-operations.js +414 -0
- package/dist/built-in-operations.js.map +1 -0
- package/dist/engine.d.ts +11 -1
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +76 -42
- package/dist/engine.js.map +1 -1
- package/dist/file-operations.d.ts +86 -0
- package/dist/file-operations.d.ts.map +1 -0
- package/dist/file-operations.js +363 -0
- package/dist/file-operations.js.map +1 -0
- package/dist/index.d.ts +6 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +29 -1
- package/dist/index.js.map +1 -1
- package/dist/logging.d.ts +40 -2
- package/dist/logging.d.ts.map +1 -1
- package/dist/logging.js +166 -13
- package/dist/logging.js.map +1 -1
- package/dist/models.d.ts +144 -8
- package/dist/models.d.ts.map +1 -1
- package/dist/models.js +15 -1
- package/dist/models.js.map +1 -1
- package/dist/nunjucks-filters.d.ts +271 -0
- package/dist/nunjucks-filters.d.ts.map +1 -0
- package/dist/nunjucks-filters.js +648 -0
- package/dist/nunjucks-filters.js.map +1 -0
- package/dist/parser.d.ts.map +1 -1
- package/dist/parser.js +16 -2
- package/dist/parser.js.map +1 -1
- package/dist/prompt-loader.d.ts +8 -2
- package/dist/prompt-loader.d.ts.map +1 -1
- package/dist/prompt-loader.js +26 -89
- package/dist/prompt-loader.js.map +1 -1
- package/dist/scheduler.d.ts +22 -3
- package/dist/scheduler.d.ts.map +1 -1
- package/dist/scheduler.js +72 -73
- package/dist/scheduler.js.map +1 -1
- package/dist/script-executor.d.ts +65 -0
- package/dist/script-executor.d.ts.map +1 -0
- package/dist/script-executor.js +261 -0
- package/dist/script-executor.js.map +1 -0
- package/dist/template-engine.d.ts +51 -0
- package/dist/template-engine.d.ts.map +1 -0
- package/dist/template-engine.js +227 -0
- package/dist/template-engine.js.map +1 -0
- package/dist/templates.d.ts +10 -0
- package/dist/templates.d.ts.map +1 -1
- package/dist/templates.js +21 -17
- package/dist/templates.js.map +1 -1
- package/package.json +16 -2
package/dist/scheduler.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../src/scheduler.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../src/scheduler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Script Executor for marktoflow v2.0
|
|
3
|
+
*
|
|
4
|
+
* Provides secure inline JavaScript execution for `script` step types.
|
|
5
|
+
* Uses Node.js `vm` module with:
|
|
6
|
+
* - Frozen context (read-only access to variables/inputs)
|
|
7
|
+
* - Configurable timeout
|
|
8
|
+
* - Safe globals (JSON, Math, Date, Array, etc.)
|
|
9
|
+
*
|
|
10
|
+
* Example usage in workflow:
|
|
11
|
+
* ```yaml
|
|
12
|
+
* - type: script
|
|
13
|
+
* inputs:
|
|
14
|
+
* code: |
|
|
15
|
+
* const items = variables.api_response.items;
|
|
16
|
+
* const filtered = items.filter(i => i.status === 'active');
|
|
17
|
+
* return { filtered, count: filtered.length };
|
|
18
|
+
* timeout: 5000
|
|
19
|
+
* output_variable: result
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export interface ScriptExecutorOptions {
|
|
23
|
+
/** Maximum execution time in milliseconds (default: 5000) */
|
|
24
|
+
timeout?: number;
|
|
25
|
+
/** Additional globals to expose to the script */
|
|
26
|
+
extraGlobals?: Record<string, unknown>;
|
|
27
|
+
}
|
|
28
|
+
export interface ScriptContext {
|
|
29
|
+
/** Workflow variables (read-only) */
|
|
30
|
+
variables: Record<string, unknown>;
|
|
31
|
+
/** Workflow inputs (read-only) */
|
|
32
|
+
inputs: Record<string, unknown>;
|
|
33
|
+
/** Step results metadata (read-only) */
|
|
34
|
+
steps?: Record<string, unknown>;
|
|
35
|
+
}
|
|
36
|
+
export interface ScriptResult {
|
|
37
|
+
/** Whether the script executed successfully */
|
|
38
|
+
success: boolean;
|
|
39
|
+
/** The return value of the script */
|
|
40
|
+
value?: unknown;
|
|
41
|
+
/** Error message if execution failed */
|
|
42
|
+
error?: string;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Execute a JavaScript code snippet in a sandboxed environment.
|
|
46
|
+
*
|
|
47
|
+
* @param code The JavaScript code to execute
|
|
48
|
+
* @param context Variables and inputs available to the script
|
|
49
|
+
* @param options Execution options (timeout, extra globals)
|
|
50
|
+
* @returns The result of script execution
|
|
51
|
+
*/
|
|
52
|
+
export declare function executeScript(code: string, context: ScriptContext, options?: ScriptExecutorOptions): ScriptResult;
|
|
53
|
+
/**
|
|
54
|
+
* Execute a script asynchronously, properly handling async code.
|
|
55
|
+
*/
|
|
56
|
+
export declare function executeScriptAsync(code: string, context: ScriptContext, options?: ScriptExecutorOptions): Promise<ScriptResult>;
|
|
57
|
+
/**
|
|
58
|
+
* Validate that a script doesn't contain dangerous patterns.
|
|
59
|
+
* This is a basic check; the VM sandbox provides the real security.
|
|
60
|
+
*/
|
|
61
|
+
export declare function validateScript(code: string): {
|
|
62
|
+
valid: boolean;
|
|
63
|
+
warnings: string[];
|
|
64
|
+
};
|
|
65
|
+
//# sourceMappingURL=script-executor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"script-executor.d.ts","sourceRoot":"","sources":["../src/script-executor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAQH,MAAM,WAAW,qBAAqB;IACpC,6DAA6D;IAC7D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iDAAiD;IACjD,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,aAAa;IAC5B,qCAAqC;IACrC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,kCAAkC;IAClC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,wCAAwC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,YAAY;IAC3B,+CAA+C;IAC/C,OAAO,EAAE,OAAO,CAAC;IACjB,qCAAqC;IACrC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,wCAAwC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA4ED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,aAAa,EACtB,OAAO,GAAE,qBAA0B,GAClC,YAAY,CAmEd;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,aAAa,EACtB,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,YAAY,CAAC,CAgEvB;AA6BD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAwBnF"}
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Script Executor for marktoflow v2.0
|
|
3
|
+
*
|
|
4
|
+
* Provides secure inline JavaScript execution for `script` step types.
|
|
5
|
+
* Uses Node.js `vm` module with:
|
|
6
|
+
* - Frozen context (read-only access to variables/inputs)
|
|
7
|
+
* - Configurable timeout
|
|
8
|
+
* - Safe globals (JSON, Math, Date, Array, etc.)
|
|
9
|
+
*
|
|
10
|
+
* Example usage in workflow:
|
|
11
|
+
* ```yaml
|
|
12
|
+
* - type: script
|
|
13
|
+
* inputs:
|
|
14
|
+
* code: |
|
|
15
|
+
* const items = variables.api_response.items;
|
|
16
|
+
* const filtered = items.filter(i => i.status === 'active');
|
|
17
|
+
* return { filtered, count: filtered.length };
|
|
18
|
+
* timeout: 5000
|
|
19
|
+
* output_variable: result
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
import * as vm from 'node:vm';
|
|
23
|
+
// ============================================================================
|
|
24
|
+
// Safe Globals
|
|
25
|
+
// ============================================================================
|
|
26
|
+
/**
|
|
27
|
+
* Safe globals available to scripts.
|
|
28
|
+
* These are frozen copies that cannot modify the original objects.
|
|
29
|
+
*/
|
|
30
|
+
const SAFE_GLOBALS = {
|
|
31
|
+
// JSON operations
|
|
32
|
+
JSON,
|
|
33
|
+
// Math operations - use the real Math object (it's already effectively immutable)
|
|
34
|
+
Math,
|
|
35
|
+
// Date operations
|
|
36
|
+
Date,
|
|
37
|
+
// Array utilities
|
|
38
|
+
Array,
|
|
39
|
+
// Object utilities
|
|
40
|
+
Object,
|
|
41
|
+
// String utilities
|
|
42
|
+
String,
|
|
43
|
+
// Number utilities
|
|
44
|
+
Number: {
|
|
45
|
+
isFinite: Number.isFinite,
|
|
46
|
+
isInteger: Number.isInteger,
|
|
47
|
+
isNaN: Number.isNaN,
|
|
48
|
+
parseFloat: Number.parseFloat,
|
|
49
|
+
parseInt: Number.parseInt,
|
|
50
|
+
},
|
|
51
|
+
// Other safe utilities
|
|
52
|
+
parseInt,
|
|
53
|
+
parseFloat,
|
|
54
|
+
isFinite,
|
|
55
|
+
isNaN,
|
|
56
|
+
encodeURIComponent,
|
|
57
|
+
decodeURIComponent,
|
|
58
|
+
encodeURI,
|
|
59
|
+
decodeURI,
|
|
60
|
+
// Console for debugging (limited to log/warn/error)
|
|
61
|
+
console: {
|
|
62
|
+
log: (...args) => console.log('[script]', ...args),
|
|
63
|
+
warn: (...args) => console.warn('[script]', ...args),
|
|
64
|
+
error: (...args) => console.error('[script]', ...args),
|
|
65
|
+
},
|
|
66
|
+
// Promise is allowed for async operations
|
|
67
|
+
Promise,
|
|
68
|
+
// Timer functions for async operations
|
|
69
|
+
setTimeout,
|
|
70
|
+
clearTimeout,
|
|
71
|
+
setInterval,
|
|
72
|
+
clearInterval,
|
|
73
|
+
// Map and Set
|
|
74
|
+
Map,
|
|
75
|
+
Set,
|
|
76
|
+
// RegExp for pattern matching
|
|
77
|
+
RegExp,
|
|
78
|
+
};
|
|
79
|
+
// ============================================================================
|
|
80
|
+
// Script Execution
|
|
81
|
+
// ============================================================================
|
|
82
|
+
/**
|
|
83
|
+
* Execute a JavaScript code snippet in a sandboxed environment.
|
|
84
|
+
*
|
|
85
|
+
* @param code The JavaScript code to execute
|
|
86
|
+
* @param context Variables and inputs available to the script
|
|
87
|
+
* @param options Execution options (timeout, extra globals)
|
|
88
|
+
* @returns The result of script execution
|
|
89
|
+
*/
|
|
90
|
+
export function executeScript(code, context, options = {}) {
|
|
91
|
+
const timeout = options.timeout ?? 5000;
|
|
92
|
+
try {
|
|
93
|
+
// Create frozen copies of context to prevent modification
|
|
94
|
+
const frozenContext = {
|
|
95
|
+
variables: deepFreeze({ ...context.variables }),
|
|
96
|
+
inputs: deepFreeze({ ...context.inputs }),
|
|
97
|
+
steps: context.steps ? deepFreeze({ ...context.steps }) : undefined,
|
|
98
|
+
};
|
|
99
|
+
// Build the sandbox with safe globals and context
|
|
100
|
+
const sandbox = {
|
|
101
|
+
...SAFE_GLOBALS,
|
|
102
|
+
...frozenContext,
|
|
103
|
+
...(options.extraGlobals ?? {}),
|
|
104
|
+
};
|
|
105
|
+
// Wrap the code in an async IIFE that returns the result
|
|
106
|
+
// This allows `return` statements and async/await
|
|
107
|
+
const wrappedCode = `
|
|
108
|
+
(async () => {
|
|
109
|
+
${code}
|
|
110
|
+
})()
|
|
111
|
+
`;
|
|
112
|
+
// Create a VM context
|
|
113
|
+
const vmContext = vm.createContext(sandbox, {
|
|
114
|
+
name: 'script-executor',
|
|
115
|
+
codeGeneration: {
|
|
116
|
+
strings: false, // Disable eval() and Function()
|
|
117
|
+
wasm: false, // Disable WebAssembly
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
// Compile and run the script
|
|
121
|
+
const script = new vm.Script(wrappedCode, {
|
|
122
|
+
filename: 'inline-script.js',
|
|
123
|
+
});
|
|
124
|
+
// Run with timeout
|
|
125
|
+
const resultPromise = script.runInContext(vmContext, {
|
|
126
|
+
timeout,
|
|
127
|
+
displayErrors: true,
|
|
128
|
+
});
|
|
129
|
+
// Handle both sync and async results
|
|
130
|
+
if (resultPromise instanceof Promise) {
|
|
131
|
+
// For async code, we need to handle the promise
|
|
132
|
+
// Since this is a sync function, we'll need to handle this specially
|
|
133
|
+
// The caller should await the result if it's a promise
|
|
134
|
+
return {
|
|
135
|
+
success: true,
|
|
136
|
+
value: resultPromise,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
return {
|
|
140
|
+
success: true,
|
|
141
|
+
value: resultPromise,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
return {
|
|
146
|
+
success: false,
|
|
147
|
+
error: error instanceof Error ? error.message : String(error),
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Execute a script asynchronously, properly handling async code.
|
|
153
|
+
*/
|
|
154
|
+
export async function executeScriptAsync(code, context, options = {}) {
|
|
155
|
+
const timeout = options.timeout ?? 5000;
|
|
156
|
+
try {
|
|
157
|
+
// Create frozen copies of context to prevent modification
|
|
158
|
+
const frozenContext = {
|
|
159
|
+
variables: deepFreeze({ ...context.variables }),
|
|
160
|
+
inputs: deepFreeze({ ...context.inputs }),
|
|
161
|
+
steps: context.steps ? deepFreeze({ ...context.steps }) : undefined,
|
|
162
|
+
};
|
|
163
|
+
// Build the sandbox with safe globals and context
|
|
164
|
+
const sandbox = {
|
|
165
|
+
...SAFE_GLOBALS,
|
|
166
|
+
...frozenContext,
|
|
167
|
+
...(options.extraGlobals ?? {}),
|
|
168
|
+
};
|
|
169
|
+
// Wrap the code in an async IIFE
|
|
170
|
+
const wrappedCode = `
|
|
171
|
+
(async () => {
|
|
172
|
+
${code}
|
|
173
|
+
})()
|
|
174
|
+
`;
|
|
175
|
+
// Create a VM context
|
|
176
|
+
const vmContext = vm.createContext(sandbox, {
|
|
177
|
+
name: 'script-executor',
|
|
178
|
+
codeGeneration: {
|
|
179
|
+
strings: false,
|
|
180
|
+
wasm: false,
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
// Compile the script
|
|
184
|
+
const script = new vm.Script(wrappedCode, {
|
|
185
|
+
filename: 'inline-script.js',
|
|
186
|
+
});
|
|
187
|
+
// Run with timeout using a race
|
|
188
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
189
|
+
setTimeout(() => reject(new Error(`Script execution timed out after ${timeout}ms`)), timeout);
|
|
190
|
+
});
|
|
191
|
+
const resultPromise = script.runInContext(vmContext, {
|
|
192
|
+
displayErrors: true,
|
|
193
|
+
});
|
|
194
|
+
// Wait for result or timeout
|
|
195
|
+
const result = await Promise.race([
|
|
196
|
+
resultPromise instanceof Promise ? resultPromise : Promise.resolve(resultPromise),
|
|
197
|
+
timeoutPromise,
|
|
198
|
+
]);
|
|
199
|
+
return {
|
|
200
|
+
success: true,
|
|
201
|
+
value: result,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
catch (error) {
|
|
205
|
+
return {
|
|
206
|
+
success: false,
|
|
207
|
+
error: error instanceof Error ? error.message : String(error),
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
// ============================================================================
|
|
212
|
+
// Utility Functions
|
|
213
|
+
// ============================================================================
|
|
214
|
+
/**
|
|
215
|
+
* Deep freeze an object to prevent any modifications.
|
|
216
|
+
*/
|
|
217
|
+
function deepFreeze(obj) {
|
|
218
|
+
if (obj === null || typeof obj !== 'object') {
|
|
219
|
+
return obj;
|
|
220
|
+
}
|
|
221
|
+
// Freeze arrays and objects recursively
|
|
222
|
+
if (Array.isArray(obj)) {
|
|
223
|
+
obj.forEach((item) => deepFreeze(item));
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
Object.keys(obj).forEach((key) => {
|
|
227
|
+
const value = obj[key];
|
|
228
|
+
if (typeof value === 'object' && value !== null) {
|
|
229
|
+
deepFreeze(value);
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
return Object.freeze(obj);
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Validate that a script doesn't contain dangerous patterns.
|
|
237
|
+
* This is a basic check; the VM sandbox provides the real security.
|
|
238
|
+
*/
|
|
239
|
+
export function validateScript(code) {
|
|
240
|
+
const warnings = [];
|
|
241
|
+
// Check for common dangerous patterns
|
|
242
|
+
const dangerousPatterns = [
|
|
243
|
+
{ pattern: /require\s*\(/, message: 'require() is not available in scripts' },
|
|
244
|
+
{ pattern: /import\s+/, message: 'import statements are not available in scripts' },
|
|
245
|
+
{ pattern: /process\./, message: 'process object is not available in scripts' },
|
|
246
|
+
{ pattern: /global\./, message: 'global object is not available in scripts' },
|
|
247
|
+
{ pattern: /globalThis\./, message: 'globalThis is not available in scripts' },
|
|
248
|
+
{ pattern: /eval\s*\(/, message: 'eval() is not available in scripts' },
|
|
249
|
+
{ pattern: /Function\s*\(/, message: 'Function constructor is not available in scripts' },
|
|
250
|
+
];
|
|
251
|
+
for (const { pattern, message } of dangerousPatterns) {
|
|
252
|
+
if (pattern.test(code)) {
|
|
253
|
+
warnings.push(message);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return {
|
|
257
|
+
valid: warnings.length === 0,
|
|
258
|
+
warnings,
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
//# sourceMappingURL=script-executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"script-executor.js","sourceRoot":"","sources":["../src/script-executor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template Engine for marktoflow v2.0
|
|
3
|
+
*
|
|
4
|
+
* Powered by Nunjucks - a powerful templating engine with Jinja2-style syntax.
|
|
5
|
+
*
|
|
6
|
+
* Features:
|
|
7
|
+
* - Variable interpolation: {{ variable }}, {{ obj.property }}, {{ arr[0] }}
|
|
8
|
+
* - Filters: {{ value | upper }}, {{ value | split('/') | first }}
|
|
9
|
+
* - Control flow: {% for item in items %}, {% if condition %}
|
|
10
|
+
* - Custom filters for regex, dates, JSON, and more (see nunjucks-filters.ts)
|
|
11
|
+
*
|
|
12
|
+
* Type preservation:
|
|
13
|
+
* - Single {{ expr }} returns the actual type (object, array, number, etc.)
|
|
14
|
+
* - Multiple expressions or mixed text returns a string
|
|
15
|
+
*/
|
|
16
|
+
import nunjucks from 'nunjucks';
|
|
17
|
+
declare const env: nunjucks.Environment;
|
|
18
|
+
/**
|
|
19
|
+
* Render a template string with context.
|
|
20
|
+
*
|
|
21
|
+
* If the entire template is a single {{expr}}, returns the raw value (object, array, etc.)
|
|
22
|
+
* Otherwise, returns the interpolated string.
|
|
23
|
+
*
|
|
24
|
+
* @param template The template string with {{ }} expressions
|
|
25
|
+
* @param context Variables available in the template
|
|
26
|
+
* @returns The resolved value (could be any type)
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* // Single expression - preserves type
|
|
30
|
+
* renderTemplate('{{ user }}', { user: { name: 'Alice' } })
|
|
31
|
+
* // Returns: { name: 'Alice' }
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* // With filters
|
|
35
|
+
* renderTemplate('{{ path | split("/") | first }}', { path: 'owner/repo' })
|
|
36
|
+
* // Returns: 'owner'
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* // String interpolation
|
|
40
|
+
* renderTemplate('Hello {{ name }}!', { name: 'World' })
|
|
41
|
+
* // Returns: 'Hello World!'
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* // Control flow
|
|
45
|
+
* renderTemplate('{% for i in items %}{{ i }}{% endfor %}', { items: [1, 2, 3] })
|
|
46
|
+
* // Returns: '123'
|
|
47
|
+
*/
|
|
48
|
+
export declare function renderTemplate(template: string, context: Record<string, unknown>): unknown;
|
|
49
|
+
/** The Nunjucks environment instance for advanced usage */
|
|
50
|
+
export { env as nunjucksEnv };
|
|
51
|
+
//# sourceMappingURL=template-engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template-engine.d.ts","sourceRoot":"","sources":["../src/template-engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,QAAQ,MAAM,UAAU,CAAC;AAQhC,QAAA,MAAM,GAAG,sBAKP,CAAC;AASH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,OAAO,CAyCT;AAmID,2DAA2D;AAC3D,OAAO,EAAE,GAAG,IAAI,WAAW,EAAE,CAAC"}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template Engine for marktoflow v2.0
|
|
3
|
+
*
|
|
4
|
+
* Powered by Nunjucks - a powerful templating engine with Jinja2-style syntax.
|
|
5
|
+
*
|
|
6
|
+
* Features:
|
|
7
|
+
* - Variable interpolation: {{ variable }}, {{ obj.property }}, {{ arr[0] }}
|
|
8
|
+
* - Filters: {{ value | upper }}, {{ value | split('/') | first }}
|
|
9
|
+
* - Control flow: {% for item in items %}, {% if condition %}
|
|
10
|
+
* - Custom filters for regex, dates, JSON, and more (see nunjucks-filters.ts)
|
|
11
|
+
*
|
|
12
|
+
* Type preservation:
|
|
13
|
+
* - Single {{ expr }} returns the actual type (object, array, number, etc.)
|
|
14
|
+
* - Multiple expressions or mixed text returns a string
|
|
15
|
+
*/
|
|
16
|
+
import nunjucks from 'nunjucks';
|
|
17
|
+
import { registerFilters } from './nunjucks-filters.js';
|
|
18
|
+
// ============================================================================
|
|
19
|
+
// Environment Setup
|
|
20
|
+
// ============================================================================
|
|
21
|
+
// Create Nunjucks environment with custom settings
|
|
22
|
+
const env = new nunjucks.Environment(null, {
|
|
23
|
+
autoescape: false, // Don't HTML escape (we're not generating HTML)
|
|
24
|
+
throwOnUndefined: false, // Return undefined for missing variables
|
|
25
|
+
trimBlocks: true, // Remove newline after block tags
|
|
26
|
+
lstripBlocks: true, // Remove whitespace before block tags
|
|
27
|
+
});
|
|
28
|
+
// Register all custom filters
|
|
29
|
+
registerFilters(env);
|
|
30
|
+
// ============================================================================
|
|
31
|
+
// Template Resolution
|
|
32
|
+
// ============================================================================
|
|
33
|
+
/**
|
|
34
|
+
* Render a template string with context.
|
|
35
|
+
*
|
|
36
|
+
* If the entire template is a single {{expr}}, returns the raw value (object, array, etc.)
|
|
37
|
+
* Otherwise, returns the interpolated string.
|
|
38
|
+
*
|
|
39
|
+
* @param template The template string with {{ }} expressions
|
|
40
|
+
* @param context Variables available in the template
|
|
41
|
+
* @returns The resolved value (could be any type)
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* // Single expression - preserves type
|
|
45
|
+
* renderTemplate('{{ user }}', { user: { name: 'Alice' } })
|
|
46
|
+
* // Returns: { name: 'Alice' }
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* // With filters
|
|
50
|
+
* renderTemplate('{{ path | split("/") | first }}', { path: 'owner/repo' })
|
|
51
|
+
* // Returns: 'owner'
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* // String interpolation
|
|
55
|
+
* renderTemplate('Hello {{ name }}!', { name: 'World' })
|
|
56
|
+
* // Returns: 'Hello World!'
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* // Control flow
|
|
60
|
+
* renderTemplate('{% for i in items %}{{ i }}{% endfor %}', { items: [1, 2, 3] })
|
|
61
|
+
* // Returns: '123'
|
|
62
|
+
*/
|
|
63
|
+
export function renderTemplate(template, context) {
|
|
64
|
+
// Check if the entire string is a single template expression
|
|
65
|
+
// Handle nested braces in object literals like {{ foo | merge({a: 1}) }}
|
|
66
|
+
const trimmed = template.trim();
|
|
67
|
+
if (trimmed.startsWith('{{') && trimmed.endsWith('}}')) {
|
|
68
|
+
// Check if there are no other {{ or }} markers (unbalanced)
|
|
69
|
+
const inner = trimmed.slice(2, -2);
|
|
70
|
+
// Count braces to ensure we only have one top-level expression
|
|
71
|
+
let braceCount = 0;
|
|
72
|
+
let hasUnbalancedTemplates = false;
|
|
73
|
+
for (let i = 0; i < inner.length; i++) {
|
|
74
|
+
if (inner[i] === '{') {
|
|
75
|
+
if (inner[i + 1] === '{') {
|
|
76
|
+
hasUnbalancedTemplates = true;
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
braceCount++;
|
|
80
|
+
}
|
|
81
|
+
else if (inner[i] === '}') {
|
|
82
|
+
if (inner[i + 1] === '}') {
|
|
83
|
+
hasUnbalancedTemplates = true;
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
braceCount--;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (!hasUnbalancedTemplates && braceCount === 0) {
|
|
90
|
+
// Single expression - return the actual value (could be object, array, etc.)
|
|
91
|
+
const expression = inner.trim();
|
|
92
|
+
return evaluateExpression(expression, context);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// String with multiple expressions, control flow, or plain text - render as string
|
|
96
|
+
try {
|
|
97
|
+
return env.renderString(template, context);
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
// If rendering fails, return the original template
|
|
101
|
+
console.error('Template render error:', error);
|
|
102
|
+
return template;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Evaluate a single expression and return its value.
|
|
107
|
+
* This is used for single {{expr}} templates where we want to preserve
|
|
108
|
+
* the actual type (object, array, number, etc.) instead of stringifying.
|
|
109
|
+
*/
|
|
110
|
+
function evaluateExpression(expression, context) {
|
|
111
|
+
try {
|
|
112
|
+
// For simple variable references (no filters or operators), use direct lookup
|
|
113
|
+
// This preserves object/array types that Nunjucks would stringify
|
|
114
|
+
const simpleVarMatch = expression.match(/^([a-zA-Z_][a-zA-Z0-9_]*)(\.[a-zA-Z_][a-zA-Z0-9_]*|\[\d+\]|\['[^']+'\]|\["[^"]+"\])*$/);
|
|
115
|
+
if (simpleVarMatch && !expression.includes('|')) {
|
|
116
|
+
// Simple variable path - resolve directly for better type preservation
|
|
117
|
+
const result = resolveVariablePath(expression, context);
|
|
118
|
+
return result !== undefined ? result : '';
|
|
119
|
+
}
|
|
120
|
+
// Check if this is an arithmetic expression (has +, -, *, /, etc. but no filters)
|
|
121
|
+
// If so, evaluate it as JavaScript for proper numeric operations
|
|
122
|
+
if (!expression.includes('|') && /[+\-*/]/.test(expression)) {
|
|
123
|
+
try {
|
|
124
|
+
// Create a safe evaluation context
|
|
125
|
+
const fn = new Function(...Object.keys(context), `return ${expression}`);
|
|
126
|
+
return fn(...Object.values(context));
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
// Fall through to Nunjucks if JavaScript evaluation fails
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
// Has filters or complex expression - use Nunjucks with JSON serialization
|
|
133
|
+
// to preserve the actual type
|
|
134
|
+
const wrappedTemplate = `{{ ${expression} | to_json }}`;
|
|
135
|
+
const jsonResult = env.renderString(wrappedTemplate, context);
|
|
136
|
+
// Parse JSON to get the actual type
|
|
137
|
+
try {
|
|
138
|
+
const parsed = JSON.parse(jsonResult);
|
|
139
|
+
return parsed;
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
// Not valid JSON (e.g., undefined, function result)
|
|
143
|
+
// Try direct rendering and return the string result
|
|
144
|
+
const directResult = env.renderString(`{{ ${expression} }}`, context);
|
|
145
|
+
return directResult || '';
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
console.error('Expression evaluation error:', error);
|
|
150
|
+
return '';
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Resolve a variable path from context (supports dot notation and array indexing).
|
|
155
|
+
* Example: "user.name", "items[0].id", "data['key']"
|
|
156
|
+
*/
|
|
157
|
+
function resolveVariablePath(path, context) {
|
|
158
|
+
const parts = [];
|
|
159
|
+
let current = '';
|
|
160
|
+
let inQuote = null;
|
|
161
|
+
for (let i = 0; i < path.length; i++) {
|
|
162
|
+
const char = path[i];
|
|
163
|
+
if (inQuote) {
|
|
164
|
+
if (char === inQuote) {
|
|
165
|
+
inQuote = null;
|
|
166
|
+
parts.push(current);
|
|
167
|
+
current = '';
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
current += char;
|
|
171
|
+
}
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
if (char === '"' || char === "'") {
|
|
175
|
+
inQuote = char;
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
if (char === '.') {
|
|
179
|
+
if (current) {
|
|
180
|
+
parts.push(current);
|
|
181
|
+
current = '';
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
else if (char === '[') {
|
|
185
|
+
if (current) {
|
|
186
|
+
parts.push(current);
|
|
187
|
+
current = '';
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
else if (char === ']') {
|
|
191
|
+
if (current) {
|
|
192
|
+
parts.push(current);
|
|
193
|
+
current = '';
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
current += char;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
if (current) {
|
|
201
|
+
parts.push(current);
|
|
202
|
+
}
|
|
203
|
+
// Traverse the object
|
|
204
|
+
let result = context;
|
|
205
|
+
for (const part of parts) {
|
|
206
|
+
if (result === null || result === undefined) {
|
|
207
|
+
return undefined;
|
|
208
|
+
}
|
|
209
|
+
const index = Number(part);
|
|
210
|
+
if (!isNaN(index) && Array.isArray(result)) {
|
|
211
|
+
result = result[index];
|
|
212
|
+
}
|
|
213
|
+
else if (typeof result === 'object') {
|
|
214
|
+
result = result[part];
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
return undefined;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return result;
|
|
221
|
+
}
|
|
222
|
+
// ============================================================================
|
|
223
|
+
// Exports
|
|
224
|
+
// ============================================================================
|
|
225
|
+
/** The Nunjucks environment instance for advanced usage */
|
|
226
|
+
export { env as nunjucksEnv };
|
|
227
|
+
//# sourceMappingURL=template-engine.js.map
|