UNPKG

open-loop-killer

Version:

Inject timeout protection into JavaScript loops to prevent infinite loops. Supports while, for, do-while, for-in, and for-of loops with customizable timeout and error messages.

56 lines (47 loc) 2.04 kB
'use strict'; const parseScript = require('esprima').parseScript; const generate = require('escodegen').generate; const injectionProcess = require('./blockInjection.js'); /** * Injects loop protection code into JavaScript source code * @param {string} code - The JavaScript code to protect * @param {Object} options - Configuration options * @param {number} [options.timeout=1000] - Timeout in milliseconds before throwing error * @param {string} [options.errorMessage='Open Loop Detected!'] - Custom error message * @returns {string} - The protected JavaScript code */ module.exports = (code, options = {}) => { let data; // Step 1: Validate user options // Ensure timeout is a positive number if provided if (options.timeout !== undefined && (typeof options.timeout !== 'number' || options.timeout <= 0)) { throw new Error('options.timeout must be a positive number'); } // Ensure errorMessage is a string if provided if (options.errorMessage !== undefined && typeof options.errorMessage !== 'string') { throw new Error('options.errorMessage must be a string'); } // Step 2: Parse JavaScript code into AST (Abstract Syntax Tree) // This validates syntax and creates a tree structure we can modify try { data = parseScript(code); } catch (err) { throw new Error('Failed to parse script due to: ' + err); } // Step 3: Traverse AST and inject timeout protection into all loops // This modifies the AST in-place, adding timer checks to each loop try { injectionProcess(data, options); } catch (err) { throw new Error('Failed to inject loop protection due to: ' + err); } // Step 4: Convert modified AST back to JavaScript code string // The result is executable JavaScript with protection injected try { data = generate(data); } catch (err) { throw new Error('Failed to generate script from AST due to: ' + err); } // Step 5: Return the protected code return data; };