<commit_before>import React from 'react';
import {httpRequestJsonLocal} from 'core/helpers/network';
import {noop} from 'lodash';

/**
 * Wraps a promise in order to ignore AbortError and break the promise chain when it occurs.
 */
function ignoreAbortError<T>(promise: Promise<T>): Promise<T> {
    return new Promise((resolve, reject) => {
        promise
            .then(resolve)
            .catch((err) => {
                if (err?.name !== 'AbortError') {
                    reject(err);
                }
            });
    });
}

export class SuperdeskReactComponent<IProps = {}, IState = {}> extends React.PureComponent<IProps, IState> {
    private abortControllers: Array<AbortController>;

    /**
     * Will automatically abort in-progress asynchronous operations(only those in asyncHelpers) when unmounting.
     */
    public asyncHelpers: {
        fetch: (input: RequestInfo, init?: RequestInit) => Promise<Response>;
        httpRequestJsonLocal: <T>(options: Parameters<typeof httpRequestJsonLocal>[0]) => Promise<T>;
    };

    constructor(props: IProps) {
        super(props);

        this.abortControllers = [];

        this.asyncHelpers = {
            fetch: (input: RequestInfo, init?: RequestInit): Promise<Response> => {
                const controller = new AbortController();

                this.abortControllers.push(controller);

                return ignoreAbortError(
                    fetch(input, {...(init ?? {}), signal: controller.signal}),
                );
            },
            httpRequestJsonLocal: (options: Parameters<typeof httpRequestJsonLocal>[0]) => {
                const controller = new AbortController();

                this.abortControllers.push(controller);

                return ignoreAbortError(
                    httpRequestJsonLocal({...options, abortSignal: controller.signal}),
                );
            },
        };

        // Save before overwriting.
        const componentWillUnmountChild = this.componentWillUnmount?.bind(this) ?? noop;

        this.componentWillUnmount = () => {
            this.abortControllers.forEach((controller) => {
                controller.abort();
            });

            componentWillUnmountChild();
        };
    }
}<commit_msg>fix abort controller scope in SuperdeskReactComponent (#3833)<commit_after>import React from 'react';
import {httpRequestJsonLocal} from 'core/helpers/network';
import {noop} from 'lodash';

/**
 * Wraps a promise in order to ignore AbortError and break the promise chain when it occurs.
 */
function ignoreAbortError<T>(promise: Promise<T>): Promise<T> {
    return new Promise((resolve, reject) => {
        promise
            .then(resolve)
            .catch((err) => {
                if (err?.name !== 'AbortError') {
                    reject(err);
                }
            });
    });
}

export class SuperdeskReactComponent<IProps = {}, IState = {}> extends React.PureComponent<IProps, IState> {
    private abortController: AbortController;

    /**
     * Will automatically abort in-progress asynchronous operations(only those in asyncHelpers) when unmounting.
     */
    public asyncHelpers: {
        fetch: (input: RequestInfo, init?: RequestInit) => Promise<Response>;
        httpRequestJsonLocal: <T>(options: Parameters<typeof httpRequestJsonLocal>[0]) => Promise<T>;
    };

    constructor(props: IProps) {
        super(props);

        const abortController = new AbortController();

        this.abortController = abortController;

        this.asyncHelpers = {
            fetch: (input: RequestInfo, init?: RequestInit): Promise<Response> => {
                return ignoreAbortError(
                    fetch(input, {...(init ?? {}), signal: abortController.signal}),
                );
            },
            httpRequestJsonLocal: (options: Parameters<typeof httpRequestJsonLocal>[0]) => {
                return ignoreAbortError(
                    httpRequestJsonLocal({...options, abortSignal: abortController.signal}),
                );
            },
        };

        // Save before overwriting.
        const componentWillUnmountChild = this.componentWillUnmount?.bind(this) ?? noop;

        this.componentWillUnmount = () => {
            abortController.abort();

            componentWillUnmountChild();
        };
    }
}
{'fraction_non_alphanumeric': 0.1192174913693901, 'fraction_numerical': 0.0018411967779056386, 'mean_word_length': 2.2505609573672403, 'pattern_counts': {'":': 0, '<': 26, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4998808', 'n_tokens_mistral': 1130, 'n_tokens_neox': 1096, 'n_words': 248}