"use strict";
/*
 * @poppinss/utils
 *
 * (c) Harminder Virk <virk@adonisjs.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.stringify = void 0;
/**
 * Exact copy of https://github.com/davidmarkclements/fast-safe-stringify/blob/master/index.js
 * with a few changes that were introduced in https://github.com/davidmarkclements/fast-safe-stringify/pull/52 PR.
 */
const arr = [];
const replacerStack = [];
// Regular stringify
function stringify(obj, replacer, spacer) {
    decirc(obj, '', [], undefined);
    let res;
    if (replacerStack.length === 0) {
        res = JSON.stringify(obj, replacer, spacer);
    }
    else {
        res = JSON.stringify(obj, replaceGetterValues(replacer), spacer);
    }
    while (arr.length !== 0) {
        var part = arr.pop();
        if (part.length === 4) {
            Object.defineProperty(part[0], part[1], part[3]);
        }
        else {
            part[0][part[1]] = part[2];
        }
    }
    return res;
}
exports.stringify = stringify;
function decirc(val, k, stack, parent) {
    let i;
    if (typeof val === 'object' && val !== null) {
        for (i = 0; i < stack.length; i++) {
            if (stack[i] === val) {
                let propertyDescriptor = Object.getOwnPropertyDescriptor(parent, k);
                if (propertyDescriptor.get !== undefined) {
                    if (propertyDescriptor.configurable) {
                        Object.defineProperty(parent, k, { value: '[Circular]' });
                        arr.push([parent, k, val, propertyDescriptor]);
                    }
                    else {
                        replacerStack.push([val, k]);
                    }
                }
                else {
                    parent[k] = '[Circular]';
                    arr.push([parent, k, val]);
                }
                return;
            }
        }
        stack.push(val);
        // Optimize for Arrays. Big arrays could kill the performance otherwise!
        if (Array.isArray(val)) {
            for (i = 0; i < val.length; i++) {
                decirc(val[i], i, stack, val);
            }
        }
        else {
            var keys = Object.keys(val);
            for (i = 0; i < keys.length; i++) {
                var key = keys[i];
                decirc(val[key], key, stack, val);
            }
        }
        stack.pop();
    }
}
// wraps replacer function to handle values we couldn't replace
// and mark them as [Circular]
function replaceGetterValues(replacer) {
    replacer =
        replacer !== undefined
            ? replacer
            : function (_, v) {
                return v;
            };
    return function (key, val) {
        if (replacerStack.length > 0) {
            for (var i = 0; i < replacerStack.length; i++) {
                var part = replacerStack[i];
                if (part[1] === key && part[0] === val) {
                    val = '[Circular]';
                    replacerStack.splice(i, 1);
                    break;
                }
            }
        }
        return replacer.call(this, key, val);
    };
}
