import { WeakCache } from "@wry/caches";
import { Trie } from "@wry/trie";
import { wrap } from "optimism";
import { checkDocument } from "@apollo/client/utilities/internal";
import { invariant } from "@apollo/client/utilities/invariant";
import { cacheSizes } from "../caching/index.js";
function identity(document) {
    return document;
}
export class DocumentTransform {
    transform;
    cached;
    resultCache = new WeakSet();
    // This default implementation of getCacheKey can be overridden by providing
    // options.getCacheKey to the DocumentTransform constructor. In general, a
    // getCacheKey function may either return an array of keys (often including
    // the document) to be used as a cache key, or undefined to indicate the
    // transform for this document should not be cached.
    getCacheKey(document) {
        return [document];
    }
    static identity() {
        // No need to cache this transform since it just returns the document
        // unchanged. This should save a bit of memory that would otherwise be
        // needed to populate the `documentCache` of this transform.
        return new DocumentTransform(identity, { cache: false });
    }
    static split(predicate, left, right = DocumentTransform.identity()) {
        return Object.assign(new DocumentTransform((document) => {
            const documentTransform = predicate(document) ? left : right;
            return documentTransform.transformDocument(document);
        }, 
        // Reasonably assume both `left` and `right` transforms handle their own caching
        { cache: false }), { left, right });
    }
    constructor(transform, options = {}) {
        this.transform = transform;
        if (options.getCacheKey) {
            // Override default `getCacheKey` function, which returns [document].
            this.getCacheKey = options.getCacheKey;
        }
        this.cached = options.cache !== false;
        this.resetCache();
    }
    /**
     * Resets the internal cache of this transform, if it has one.
     */
    resetCache() {
        if (this.cached) {
            const stableCacheKeys = new Trie();
            this.performWork = wrap(DocumentTransform.prototype.performWork.bind(this), {
                makeCacheKey: (document) => {
                    const cacheKeys = this.getCacheKey(document);
                    if (cacheKeys) {
                        invariant(Array.isArray(cacheKeys), 20);
                        return stableCacheKeys.lookupArray(cacheKeys);
                    }
                },
                max: cacheSizes["documentTransform.cache"],
                cache: (WeakCache),
            });
        }
    }
    performWork(document) {
        checkDocument(document);
        return this.transform(document);
    }
    transformDocument(document) {
        // If a user passes an already transformed result back to this function,
        // immediately return it.
        if (this.resultCache.has(document)) {
            return document;
        }
        const transformedDocument = this.performWork(document);
        this.resultCache.add(transformedDocument);
        return transformedDocument;
    }
    concat(otherTransform) {
        return Object.assign(new DocumentTransform((document) => {
            return otherTransform.transformDocument(this.transformDocument(document));
        }, 
        // Reasonably assume both transforms handle their own caching
        { cache: false }), {
            left: this,
            right: otherTransform,
        });
    }
    /**
    * @internal
    * Used to iterate through all transforms that are concatenations or `split` links.
    * 
    * @deprecated This is an internal API and should not be used directly. This can be removed or changed at any time.
    */
    left;
    /**
    * @internal
    * Used to iterate through all transforms that are concatenations or `split` links.
    * 
    * @deprecated This is an internal API and should not be used directly. This can be removed or changed at any time.
    */
    right;
}
//# sourceMappingURL=DocumentTransform.js.map
