export { parse } from "./_toml/parser.ts";
function joinKeys(keys) {
    return keys
        .map((str) => {
        return str.match(/[^A-Za-z0-9_-]/) ? JSON.stringify(str) : str;
    })
        .join(".");
}
var ArrayType;
(function (ArrayType) {
    ArrayType[ArrayType["ONLY_PRIMITIVE"] = 0] = "ONLY_PRIMITIVE";
    ArrayType[ArrayType["ONLY_OBJECT_EXCLUDING_ARRAY"] = 1] = "ONLY_OBJECT_EXCLUDING_ARRAY";
    ArrayType[ArrayType["MIXED"] = 2] = "MIXED";
})(ArrayType || (ArrayType = {}));
class Dumper {
    maxPad = 0;
    srcObject;
    output = [];
    #arrayTypeCache = new Map();
    constructor(srcObjc) {
        this.srcObject = srcObjc;
    }
    dump(fmtOptions = {}) {
        this.output = this.#printObject(this.srcObject);
        this.output = this.#format(fmtOptions);
        return this.output;
    }
    #printObject(obj, keys = []) {
        const out = [];
        const props = Object.keys(obj);
        const inlineProps = [];
        const multilineProps = [];
        for (const prop of props) {
            if (this.#isSimplySerializable(obj[prop])) {
                inlineProps.push(prop);
            }
            else {
                multilineProps.push(prop);
            }
        }
        const sortedProps = inlineProps.concat(multilineProps);
        for (let i = 0; i < sortedProps.length; i++) {
            const prop = sortedProps[i];
            const value = obj[prop];
            if (value instanceof Date) {
                out.push(this.#dateDeclaration([prop], value));
            }
            else if (typeof value === "string" || value instanceof RegExp) {
                out.push(this.#strDeclaration([prop], value.toString()));
            }
            else if (typeof value === "number") {
                out.push(this.#numberDeclaration([prop], value));
            }
            else if (typeof value === "boolean") {
                out.push(this.#boolDeclaration([prop], value));
            }
            else if (value instanceof Array) {
                const arrayType = this.#getTypeOfArray(value);
                if (arrayType === ArrayType.ONLY_PRIMITIVE) {
                    out.push(this.#arrayDeclaration([prop], value));
                }
                else if (arrayType === ArrayType.ONLY_OBJECT_EXCLUDING_ARRAY) {
                    for (let i = 0; i < value.length; i++) {
                        out.push("");
                        out.push(this.#headerGroup([...keys, prop]));
                        out.push(...this.#printObject(value[i], [...keys, prop]));
                    }
                }
                else {
                    const str = value.map((x) => this.#printAsInlineValue(x)).join(",");
                    out.push(`${this.#declaration([prop])}[${str}]`);
                }
            }
            else if (typeof value === "object") {
                out.push("");
                out.push(this.#header([...keys, prop]));
                if (value) {
                    const toParse = value;
                    out.push(...this.#printObject(toParse, [...keys, prop]));
                }
            }
        }
        out.push("");
        return out;
    }
    #isPrimitive(value) {
        return value instanceof Date ||
            value instanceof RegExp ||
            ["string", "number", "boolean"].includes(typeof value);
    }
    #getTypeOfArray(arr) {
        if (this.#arrayTypeCache.has(arr)) {
            return this.#arrayTypeCache.get(arr);
        }
        const type = this.#doGetTypeOfArray(arr);
        this.#arrayTypeCache.set(arr, type);
        return type;
    }
    #doGetTypeOfArray(arr) {
        if (!arr.length) {
            return ArrayType.ONLY_PRIMITIVE;
        }
        const onlyPrimitive = this.#isPrimitive(arr[0]);
        if (arr[0] instanceof Array) {
            return ArrayType.MIXED;
        }
        for (let i = 1; i < arr.length; i++) {
            if (onlyPrimitive !== this.#isPrimitive(arr[i]) || arr[i] instanceof Array) {
                return ArrayType.MIXED;
            }
        }
        return onlyPrimitive
            ? ArrayType.ONLY_PRIMITIVE
            : ArrayType.ONLY_OBJECT_EXCLUDING_ARRAY;
    }
    #printAsInlineValue(value) {
        if (value instanceof Date) {
            return `"${this.#printDate(value)}"`;
        }
        else if (typeof value === "string" || value instanceof RegExp) {
            return JSON.stringify(value.toString());
        }
        else if (typeof value === "number") {
            return value;
        }
        else if (typeof value === "boolean") {
            return value.toString();
        }
        else if (value instanceof Array) {
            const str = value.map((x) => this.#printAsInlineValue(x)).join(",");
            return `[${str}]`;
        }
        else if (typeof value === "object") {
            if (!value) {
                throw new Error("should never reach");
            }
            const str = Object.keys(value).map((key) => {
                return `${key} = ${this.#printAsInlineValue(value[key])}`;
            }).join(",");
            return `{${str}}`;
        }
        throw new Error("should never reach");
    }
    #isSimplySerializable(value) {
        return (typeof value === "string" ||
            typeof value === "number" ||
            typeof value === "boolean" ||
            value instanceof RegExp ||
            value instanceof Date ||
            (value instanceof Array &&
                this.#getTypeOfArray(value) !== ArrayType.ONLY_OBJECT_EXCLUDING_ARRAY));
    }
    #header(keys) {
        return `[${joinKeys(keys)}]`;
    }
    #headerGroup(keys) {
        return `[[${joinKeys(keys)}]]`;
    }
    #declaration(keys) {
        const title = joinKeys(keys);
        if (title.length > this.maxPad) {
            this.maxPad = title.length;
        }
        return `${title} = `;
    }
    #arrayDeclaration(keys, value) {
        return `${this.#declaration(keys)}${JSON.stringify(value)}`;
    }
    #strDeclaration(keys, value) {
        return `${this.#declaration(keys)}${JSON.stringify(value)}`;
    }
    #numberDeclaration(keys, value) {
        switch (value) {
            case Infinity:
                return `${this.#declaration(keys)}inf`;
            case -Infinity:
                return `${this.#declaration(keys)}-inf`;
            default:
                return `${this.#declaration(keys)}${value}`;
        }
    }
    #boolDeclaration(keys, value) {
        return `${this.#declaration(keys)}${value}`;
    }
    #printDate(value) {
        function dtPad(v, lPad = 2) {
            return v.padStart(lPad, "0");
        }
        const m = dtPad((value.getUTCMonth() + 1).toString());
        const d = dtPad(value.getUTCDate().toString());
        const h = dtPad(value.getUTCHours().toString());
        const min = dtPad(value.getUTCMinutes().toString());
        const s = dtPad(value.getUTCSeconds().toString());
        const ms = dtPad(value.getUTCMilliseconds().toString(), 3);
        const fData = `${value.getUTCFullYear()}-${m}-${d}T${h}:${min}:${s}.${ms}`;
        return fData;
    }
    #dateDeclaration(keys, value) {
        return `${this.#declaration(keys)}${this.#printDate(value)}`;
    }
    #format(options = {}) {
        const { keyAlignment = false } = options;
        const rDeclaration = /^(\".*\"|[^=]*)\s=/;
        const out = [];
        for (let i = 0; i < this.output.length; i++) {
            const l = this.output[i];
            if (l[0] === "[" && l[1] !== "[") {
                if (this.output[i + 1] === "") {
                    i += 1;
                    continue;
                }
                out.push(l);
            }
            else {
                if (keyAlignment) {
                    const m = rDeclaration.exec(l);
                    if (m) {
                        out.push(l.replace(m[1], m[1].padEnd(this.maxPad)));
                    }
                    else {
                        out.push(l);
                    }
                }
                else {
                    out.push(l);
                }
            }
        }
        const cleanedOutput = [];
        for (let i = 0; i < out.length; i++) {
            const l = out[i];
            if (!(l === "" && out[i + 1] === "")) {
                cleanedOutput.push(l);
            }
        }
        return cleanedOutput;
    }
}
export function stringify(srcObj, fmtOptions) {
    return new Dumper(srcObj).dump(fmtOptions).join("\n");
}
//# sourceMappingURL=data:application/json;base64,[encoded data, 23928 characters]