Repository: puppeteer/puppeteer
File: packages/puppeteer-core/src/cdp/ExecutionContext.ts (TypeScript)

Code before:
    this._client = client;
    this._world = world;
    this._contextId = contextPayload.id;
    if (contextPayload.name) {
      this._contextName = contextPayload.name;
    }
  }

  #bindingsInstalled = false;
  #puppeteerUtil?: Promise<JSHandle<PuppeteerUtil>>;
  get puppeteerUtil(): Promise<JSHandle<PuppeteerUtil>> {
    let promise = Promise.resolve() as Promise<unknown>;
    if (!this.#bindingsInstalled) {
      promise = Promise.all([
        this.#installGlobalBinding(
          new Binding(
            '__ariaQuerySelector',
            ARIAQueryHandler.queryOne as (...args: unknown[]) => unknown
          )
        ),
        this.#installGlobalBinding(
          new Binding('__ariaQuerySelectorAll', (async (
            element: ElementHandle<Node>,
            selector: string
          ): Promise<JSHandle<Node[]>> => {
            const results = ARIAQueryHandler.queryAll(element, selector);
            return await element.realm.evaluateHandle(
              (...elements) => {
                return elements;
              },
              ...(await AsyncIterableUtil.collect(results))
            );
          }) as (...args: unknown[]) => unknown)
        ),
      ]);
      this.#bindingsInstalled = true;
    }
    scriptInjector.inject(script => {
      if (this.#puppeteerUtil) {
        void this.#puppeteerUtil.then(handle => {
          void handle.dispose();
        });
      }
      this.#puppeteerUtil = promise.then(() => {
        return this.evaluateHandle(script) as Promise<JSHandle<PuppeteerUtil>>;
      });
    }, !this.#puppeteerUtil);
    return this.#puppeteerUtil as Promise<JSHandle<PuppeteerUtil>>;
  }

  async #installGlobalBinding(binding: Binding) {

Review comment (suggestion):
Nit: we only use it in this class now. 
```suggestion
  async #addBindingToContext(name: string): Promise<void> {
```

Code after:
  _contextName?: string;

  constructor(
    client: CDPSession,
    contextPayload: Protocol.Runtime.ExecutionContextDescription,
    world: IsolatedWorld
  ) {
    this._client = client;
    this._world = world;
    this._contextId = contextPayload.id;
    if (contextPayload.name) {
      this._contextName = contextPayload.name;
    }
    this._client.on('Runtime.bindingCalled', this.#onBindingCalled);
  }

  // Set of bindings that have been registered in the current context.
  #contextBindings = new Set<string>();

  // Contains mapping from functions that should be bound to Puppeteer functions.
  #bindings = new Map<string, Binding>();

  // If multiple waitFor are set up asynchronously, we need to wait for the
  // first one to set up the binding in the page before running the others.
  #mutex = new Mutex();
  async _addBindingToContext(name: string): Promise<void> {
    if (this.#contextBindings.has(name)) {
      return;
    }

    using _ = await this.#mutex.acquire();
    try {
      await this._client.send(
        'Runtime.addBinding',
        this._contextName
          ? {
              name,
              executionContextName: this._contextName,
            }
          : {
              name,
              executionContextId: this._contextId,
            }
      );

      await this.evaluate(addPageBinding, 'internal', name);

      this.#contextBindings.add(name);
    } catch (error) {
      // We could have tried to evaluate in a context which was already
      // destroyed. This happens, for example, if the page is navigated while