"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.normalizePropertyNames = void 0;
const camelCase_1 = __importDefault(require("lodash/camelCase"));
const isString = (x) => typeof x === 'string';
const isBool = (x) => typeof x === 'boolean';
const isReal = (x) => typeof x === 'number';
const isInt = (x) => typeof x === 'number' && x - Math.floor(x) === 0;
const isDate = (x) => {
    if (!x) {
        return false;
    }
    if (x.constructor === Date) {
        return !isNaN(x);
    }
    return false;
};
const isArrayOf = (f) => {
    return function (x) {
        if (!(x instanceof Array)) {
            return false;
        }
        for (let i = 0; i < x.length; i++) {
            if (!f(x[i])) {
                return false;
            }
        }
        return true;
    };
};
const isObject = (x) => x && typeof x === 'object';
const typeValidators = {
    str: isString,
    bool: isBool,
    real: isReal,
    int: isInt,
    date: isDate,
    strs: isArrayOf(isString),
    bools: isArrayOf(isBool),
    reals: isArrayOf(isReal),
    ints: isArrayOf(isInt),
    dates: isArrayOf(isDate),
    objs: isArrayOf(isObject),
    obj: isObject
};
const inferType = (value) => {
    for (const t in typeValidators) {
        if (typeValidators[t](value)) {
            return t;
        }
    }
    return null;
};
const isKnownTypeSuffix = (suffix) => !!typeValidators[suffix];
const invalidPropertyNameCharRegex = /[^A-Za-z0-9_]/g;
const stripCharsNotSupportedInPropertyNames = (text) => {
    return text.replace(invalidPropertyNameCharRegex, '');
};
const typeSuffixPropertyName = (name, value) => {
    const valueTypeName = typeof value;
    if (valueTypeName === 'undefined') {
        return name;
    }
    const lastUnderscore = name.lastIndexOf('_');
    if (lastUnderscore === -1 || !isKnownTypeSuffix(name.substring(lastUnderscore + 1))) {
        const maybeType = inferType(value);
        if (maybeType === null || maybeType === 'obj') {
            return name;
        }
        return `${name}_${maybeType}`;
    }
    return name;
};
const transformPropertyName = (name, transformations) => {
    const parts = name.split('_');
    const transform = (original) => transformations.reduce((target, transformation) => {
        return transformation(target);
    }, original);
    if (parts.length > 1) {
        const typeSuffix = parts.pop();
        if (typeSuffix && typeValidators[typeSuffix]) {
            return transform(parts.join('_')) + `_${typeSuffix}`;
        }
    }
    return transform(name);
};
const MAX_PROPERTY_NORMALIZATION_DEPTH = 5;
const recursivelyTransformPropertyNames = (obj, transformPropertyName, currentDepth) => {
    if (currentDepth > MAX_PROPERTY_NORMALIZATION_DEPTH) {
        return obj;
    }
    const normalizedObj = {};
    Object.entries(obj).forEach(([key, value]) => {
        const normalizedName = transformPropertyName(key, value);
        normalizedObj[normalizedName] =
            inferType(value) === 'obj'
                ? recursivelyTransformPropertyNames(value, transformPropertyName, currentDepth + 1)
                : value;
    });
    return normalizedObj;
};
const normalizePropertyNames = (obj, options) => {
    if (!obj) {
        return {};
    }
    const transformations = [];
    if (options?.camelCase) {
        transformations.push(camelCase_1.default);
    }
    transformations.push(stripCharsNotSupportedInPropertyNames);
    const normalizePropertyName = (name, value) => {
        const transformedName = transformPropertyName(name, transformations);
        return options?.typeSuffix ? typeSuffixPropertyName(transformedName, value) : transformedName;
    };
    return recursivelyTransformPropertyNames(obj, normalizePropertyName, 1);
};
exports.normalizePropertyNames = normalizePropertyNames;
//# sourceMappingURL=vars.js.map