UNPKG

@comake/skl-js-engine

Version:

Standard Knowledge Language Javascript Engine

217 lines (188 loc) 6.68 kB
// executor.ts - Updated for current Deno versions // Set up process communication const decoder = new TextDecoder(); const encoder = new TextEncoder(); // Function to safely stringify any value function safeStringify(obj, indent = 2) { const cache = new Set(); return JSON.stringify( obj, (key, value) => { if (typeof value === 'object' && value !== null) { if (cache.has(value)) { return '[Circular Reference]'; } cache.add(value); } // Handle special types that don't stringify well if (value instanceof Error) { return { name: value.name, message: value.message, stack: value.stack }; } if (value instanceof RegExp || value instanceof Date) { return value.toString(); } if (typeof value === 'function') { return `[Function: ${value.name || 'anonymous'}]`; } return value; }, indent, ); } // Import available plugins // import { toArrayBuffer } from 'https://deno.land/std/streams/mod.ts'; import { Buffer } from 'node:buffer'; import { arrayBuffer } from 'node:stream/consumers'; // Define utility functions const utils = { formatDate: (date, format = 'ISO') => { const dateObj = date instanceof Date ? date : new Date(date); if (format === 'ISO') return dateObj.toISOString(); if (format === 'UTC') return dateObj.toUTCString(); return dateObj.toString(); }, slugify: (text) => { return text .toLowerCase() .replace(/\s+/g, '-') .replace(/[^\w\-]+/g, '') .replace(/\-\-+/g, '-'); }, groupBy: (array, key) => { return array.reduce((result, item) => { const groupKey = item[key]; if (!result[groupKey]) { result[groupKey] = []; } result[groupKey].push(item); return result; }, {}); }, }; // Check if code contains a function definition function containsNamedFunction(code, functionName) { // Look for function declarations const functionRegex = new RegExp(`function\\s+${functionName}\\s*\\(`, 'g'); if (functionRegex.test(code)) return true; // Look for arrow functions or function expressions const arrowFunctionRegex = new RegExp(`(const|let|var)\\s+${functionName}\\s*=\\s*(async\\s+)?\\(?.*\\)?\\s*=>`, 'g'); if (arrowFunctionRegex.test(code)) return true; // Look for object method definitions const methodRegex = new RegExp(`${functionName}\\s*\\(.*\\)\\s*{`, 'g'); if (methodRegex.test(code)) return true; return false; } // Main execution function async function executeCode() { try { // Read input from stdin - updated for current Deno versions const logs = []; const inputText = decoder.decode(await arrayBuffer(Deno.stdin.readable)); const decodedText = Buffer.from(inputText, 'base64'); const decodedData = decoder.decode(decodedText); // Deno.writeTextFileSync('/Users/avneeshraghav/Downloads/deno.txt', decodedData); const inputData = JSON.parse(decodedData); // Extract execution details const { code, args, functionName = 'main', skdsEndpointUrl } = inputData; const sklEngine = new SKLEngine({ type: "sparql", endpointUrl: skdsEndpointUrl, }); // Setup execution environment // Custom console implementation const console = { log: (...args) => { logs.push(args.map((arg) => (typeof arg === 'object' ? safeStringify(arg) : String(arg))).join(' ')); }, error: (...args) => { logs.push( `ERROR: ${args.map((arg) => (typeof arg === 'object' ? safeStringify(arg) : String(arg))).join(' ')}`, ); }, warn: (...args) => { logs.push(`WARN: ${args.map((arg) => (typeof arg === 'object' ? safeStringify(arg) : String(arg))).join(' ')}`); }, info: (...args) => { logs.push(`INFO: ${args.map((arg) => (typeof arg === 'object' ? safeStringify(arg) : String(arg))).join(' ')}`); }, }; // Result object const result = { logs, error: null, result: null, executionTime: 0, }; try { const startTime = performance.now(); // Wrap code execution in an async function to allow top-level await const AsyncFunction = Object.getPrototypeOf(async function () {}).constructor; // Determine how to handle the code let finalCode = code; const hasNamedFunction = containsNamedFunction(code, functionName); // If no main function is defined, wrap the code if (!hasNamedFunction) { // Check if the code is a simple expression (no statements ending with ;) const isSimpleExpression = !code.includes(';') && !code.includes('function') && !code.includes('class') && !code.includes('if') && !code.includes('for') && !code.trim().startsWith('//'); if (isSimpleExpression) { // For simple expressions, return the evaluated result directly finalCode = `function ${functionName}() { return (${code}); }`; } else { // For code blocks, wrap everything in a function finalCode = `function ${functionName}() {\n${code}\n}`; } } // Create the execution function with the processed code const executeFn = new AsyncFunction( 'args', 'console', 'utils', 'sklEngine', ` ${finalCode} // Return result from the specified function if (typeof ${functionName} === 'function') { return ${functionName}(); } else { throw new Error("Function '${functionName}' is not defined"); } `, ); // Execute with the provided context result.result = await executeFn(args, console, utils, sklEngine); result.executionTime = performance.now() - startTime; } catch (error) { result.error = { message: error.message || 'Unknown execution error', name: error.name, stack: error.stack, }; } // Write result to stdout - updated for current Deno versions await Deno.stdout.write(encoder.encode(safeStringify(result))); } catch (err) { // Handle errors in the outer execution context const errorResult = { logs: [], error: { message: `Error in Deno execution context: ${err.message}`, name: err.name, stack: err.stack, }, result: null, executionTime: 0, }; await Deno.stdout.write(encoder.encode(JSON.stringify(errorResult))); } } // Execute and catch any top-level errors executeCode().catch((err) => { console.error('Fatal error:', err); Deno.exit(1); });