UNPKG

@cloudflare/puppeteer

Version:

A high-level API to control headless Chrome over the DevTools Protocol

96 lines 3.11 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.interpolateFunction = exports.stringifyFunction = exports.createFunction = void 0; /** * @license * Copyright 2023 Google Inc. * SPDX-License-Identifier: Apache-2.0 */ const createdFunctions = new Map(); /** * Creates a function from a string. * * @internal */ const createFunction = (functionValue) => { let fn = createdFunctions.get(functionValue); if (fn) { return fn; } fn = new Function(`return ${functionValue}`)(); createdFunctions.set(functionValue, fn); return fn; }; exports.createFunction = createFunction; /** * @internal */ function stringifyFunction(fn) { let value; if (typeof fn === 'function' && globalThis.navigator?.userAgent === 'Cloudflare-Workers') { // function is most likely bundled with wrangler, // which uses esbuild with keepNames enabled. // See: https://github.com/cloudflare/workers-sdk/issues/7107 value = `((__name => (${fn}))(t => t))`; } else { value = fn.toString(); } /** * We remove the check for the ability for dynamic javascript to be * serializable, because the Workers runtime does not allow dynamic * javascript to be executed, as a security precaution. In the * future, we can consider the serialization check in the back end * but before the message gets to the remote browser. */ // original implementationn // try { // new Function(`(${value})`); // } catch { // // This means we might have a function shorthand (e.g. `test(){}`). Let's // // try prefixing. // let prefix = 'function '; // if (value.startsWith('async ')) { // prefix = `async ${prefix}`; // value = value.substring('async '.length); // } // value = `${prefix}${value}`; // try { // new Function(`(${value})`); // } catch { // console.log('functions::::', value); // // We tried hard to serialize, but there's a weird beast here. // throw new Error('Passed function cannot be serialized!'); // } // } return value; } exports.stringifyFunction = stringifyFunction; /** * Replaces `PLACEHOLDER`s with the given replacements. * * All replacements must be valid JS code. * * @example * * ```ts * interpolateFunction(() => PLACEHOLDER('test'), {test: 'void 0'}); * // Equivalent to () => void 0 * ``` * * @internal */ const interpolateFunction = (fn, replacements) => { let value = stringifyFunction(fn); for (const [name, jsValue] of Object.entries(replacements)) { value = value.replace(new RegExp(`PLACEHOLDER\\(\\s*(?:'${name}'|"${name}")\\s*\\)`, 'g'), // Wrapping this ensures tersers that accidentally inline PLACEHOLDER calls // are still valid. Without, we may get calls like ()=>{...}() which is // not valid. `(${jsValue})`); } return (0, exports.createFunction)(value); }; exports.interpolateFunction = interpolateFunction; //# sourceMappingURL=Function.js.map