{"ScriptPreparationCode":"const filters = new Map();\r\nconst limiters = new Map();\r\n\r\nfunction filter(name, handler) {\r\n if (typeof name !== \u0027string\u0027) {\r\n throw new TypeError(\u0027First argument must be a string.\u0027);\r\n }\r\n if (typeof handler !== \u0027function\u0027) {\r\n throw new TypeError(\u0027Second argument must be a function.\u0027);\r\n }\r\n if (filters.has(name)) {\r\n throw new Error(\u0060A filter named ${name} is already registered.\u0060);\r\n }\r\n filters.set(name, handler);\r\n}\r\n\r\nfunction limiter(name, handler) {\r\n if (typeof name !== \u0027string\u0027) {\r\n throw new TypeError(\u0027First argument must be a string.\u0027);\r\n }\r\n if (typeof handler !== \u0027function\u0027) {\r\n throw new TypeError(\u0027Second argument must be a function.\u0027);\r\n }\r\n if (limiters.has(name)) {\r\n throw new Error(\u0060A limiter named ${name} is already registered.\u0060);\r\n }\r\n limiters.set(name, handler);\r\n}\r\n\r\nfunction compileRawExpression(src) {\r\n return new Function(\u0027context\u0027, \u0027tempVars\u0027, // eslint-disable-line\r\n \u0060const sandbox = $nxCompileToSandbox(context, tempVars)\r\n try { with (sandbox) { return ${src} } } catch (err) {\r\n if (!(err instanceof TypeError)) throw err\r\n }\r\n $nxClearSandbox()\u0060);\r\n}\r\n\r\nfunction compileRawCode(src) {\r\n return new Function(\u0027context\u0027, \u0027tempVars\u0027, // eslint-disable-line\r\n \u0060const sandbox = $nxCompileToSandbox(context, tempVars)\r\n with (sandbox) { ${src} }\r\n $nxClearSandbox()\u0060);\r\n}\r\n\r\nconst filterRegex = /(?:[^\\|]|\\|\\|)\u002B/g;\r\nconst limiterRegex = /(?:[^\u0026]|\u0026\u0026)\u002B/g;\r\nconst argsRegex = /\\S\u002B/g;\r\n\r\nfunction parseExpression(src) {\r\n const tokens = src.match(filterRegex);\r\n if (tokens.length === 1) {\r\n return compileRawExpression(tokens[0]);\r\n }\r\n\r\n const expression = {\r\n exec: compileRawExpression(tokens[0]),\r\n filters: []\r\n };\r\n for (let i = 1; i \u003C tokens.length; i\u002B\u002B) {\r\n let filterTokens = tokens[i].match(argsRegex);\r\n const filterName = filterTokens.shift();\r\n const effect = filters.get(filterName);\r\n if (!effect) {\r\n throw new Error(\u0060There is no filter named: ${filterName}.\u0060);\r\n }\r\n expression.filters.push({ effect, argExpressions: filterTokens.map(compileRawExpression) });\r\n }\r\n return expression;\r\n}\r\n\r\nfunction parseCode(src) {\r\n const tokens = src.match(limiterRegex);\r\n if (tokens.length === 1) {\r\n return compileRawCode(tokens[0]);\r\n }\r\n\r\n const code = {\r\n exec: compileRawCode(tokens[0]),\r\n limiters: []\r\n };\r\n for (let i = 1; i \u003C tokens.length; i\u002B\u002B) {\r\n const limiterTokens = tokens[i].match(argsRegex);\r\n const limiterName = limiterTokens.shift();\r\n const effect = limiters.get(limiterName);\r\n if (!effect) {\r\n throw new Error(\u0060There is no limiter named: ${limiterName}.\u0060);\r\n }\r\n code.limiters.push({ effect, argExpressions: limiterTokens.map(compileRawExpression) });\r\n }\r\n return code;\r\n}\r\n\r\nconst expressionCache = new Map();\r\nconst codeCache = new Map();\r\n\r\nfunction compileExpression(src) {\r\n if (typeof src !== \u0027string\u0027) {\r\n throw new TypeError(\u0027First argument must be a string.\u0027);\r\n }\r\n let expression = expressionCache.get(src);\r\n if (!expression) {\r\n expression = parseExpression(src);\r\n expressionCache.set(src, expression);\r\n }\r\n\r\n if (typeof expression === \u0027function\u0027) {\r\n return expression;\r\n }\r\n\r\n return function evaluateExpression(context, tempVars) {\r\n let value = expression.exec(context, tempVars);\r\n for (let filter of expression.filters) {\r\n const args = filter.argExpressions.map(evaluateArgExpression, context);\r\n value = filter.effect(value, ...args);\r\n }\r\n return value;\r\n };\r\n}\r\n\r\nfunction compileCode(src) {\r\n if (typeof src !== \u0027string\u0027) {\r\n throw new TypeError(\u0027First argument must be a string.\u0027);\r\n }\r\n let code = codeCache.get(src);\r\n if (!code) {\r\n code = parseCode(src);\r\n codeCache.set(src, code);\r\n }\r\n\r\n if (typeof code === \u0027function\u0027) {\r\n return code;\r\n }\r\n\r\n const context = {};\r\n return function evaluateCode(state, tempVars) {\r\n let i = 0;\r\n function next() {\r\n Object.assign(context, tempVars);\r\n if (i \u003C code.limiters.length) {\r\n const limiter = code.limiters[i\u002B\u002B];\r\n const args = limiter.argExpressions.map(evaluateArgExpression, state);\r\n limiter.effect(next, context, ...args);\r\n } else {\r\n code.exec(state, tempVars);\r\n }\r\n }\r\n next();\r\n };\r\n}\r\n\r\nfunction evaluateArgExpression(argExpression) {\r\n return argExpression(this);\r\n}\r\n\r\nconst hasHandler = { has };\r\nconst allHandlers = { has, get };\r\nconst globals = new Set();\r\nlet temp;\r\n\r\nlet globalObj;\r\nif (typeof window !== \u0027undefined\u0027) globalObj = window; // eslint-disable-line\r\nelse if (typeof global !== \u0027undefined\u0027) globalObj = global; // eslint-disable-line\r\n else if (typeof self !== \u0027undefined\u0027) globalObj = self; // eslint-disable-line\r\nglobalObj.$nxCompileToSandbox = toSandbox;\r\nglobalObj.$nxClearSandbox = clearSandbox;\r\n\r\nfunction expose(...globalNames) {\r\n for (let globalName of globalNames) {\r\n globals.add(globalName);\r\n }\r\n}\r\n\r\nfunction hide(...globalNames) {\r\n for (let globalName of globalNames) {\r\n globals.delete(globalName);\r\n }\r\n}\r\n\r\nfunction hideAll() {\r\n globals.clear();\r\n}\r\n\r\nfunction has(target, key) {\r\n return globals.has(key) ? key in target : true;\r\n}\r\n\r\nfunction get(target, key) {\r\n return key in temp ? temp[key] : target[key];\r\n}\r\n\r\nfunction toSandbox(obj, tempVars) {\r\n if (tempVars) {\r\n temp = tempVars;\r\n return new Proxy(obj, allHandlers);\r\n }\r\n return new Proxy(obj, hasHandler);\r\n}\r\n\r\nfunction clearSandbox() {\r\n temp = undefined;\r\n}\r\nwindow.codeopti = compileCode(\u0027return prop1 \u002B prop2\u0027);","TestCases":[{"Name":"Compile and exec","Code":"const code = compileCode(\u0027return prop1 \u002B prop2\u0027);\r\nconst sum = code({prop1: 1, prop2: 2});","IsDeferred":false},{"Name":"Eval","Code":"eval(\u00271\u002B2\u0027);","IsDeferred":false},{"Name":"Exec only","Code":"const sum = codeopti({prop1: 1, prop2: 2});","IsDeferred":false}]}