"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ConfigTransformer = void 0;
const ts_morph_1 = require("ts-morph");
class ConfigTransformer {
    constructor(content) {
        this.project = new ts_morph_1.Project({
            compilerOptions: {
                allowJs: true,
            },
        });
        this.scriptKind = content.includes("module.exports")
            ? ts_morph_1.ScriptKind.JS
            : ts_morph_1.ScriptKind.TS;
        this.config = this.project.createSourceFile("virtual_nativescript.config.ts", content, {
            scriptKind: this.scriptKind,
        });
    }
    getDefaultExportValue() {
        let exportValue;
        if (this.scriptKind === ts_morph_1.ScriptKind.JS) {
            this.config.getStatements().find((statement) => {
                try {
                    if (statement.getKind() === ts_morph_1.SyntaxKind.ExpressionStatement) {
                        const expression = statement.getExpressionIfKind(ts_morph_1.SyntaxKind.BinaryExpression);
                        const leftSide = expression.getLeft();
                        if (leftSide.getFullText().trim() === "module.exports") {
                            exportValue = expression.getRight();
                            return true;
                        }
                    }
                }
                catch (err) {
                    return false;
                }
            });
        }
        else {
            const exports = this.config
                .getDefaultExportSymbolOrThrow()
                .getDeclarations()[0];
            const expr = exports.getExpression();
            exportValue =
                expr.getChildCount() > 0
                    ? expr.getChildAtIndex(0)
                    : expr;
        }
        if (!ts_morph_1.Node.isObjectLiteralExpression(exportValue)) {
            throw new Error("default export must be an object!");
        }
        return exportValue;
    }
    getProperty(key, parent = null) {
        if (key.includes(".")) {
            const parts = key.split(".");
            const name = parts.shift();
            const property = this.getProperty(name, parent);
            // no android key, add it to parent to root
            if (!property) {
                return undefined;
            }
            const _parent = property.getLastChild((child) => {
                return ts_morph_1.Node.isObjectLiteralExpression(child);
            });
            if (!_parent) {
                return undefined;
            }
            // add nonExistent.deep to android: {}
            return this.getProperty(parts.join("."), _parent);
        }
        // if we have a parent, we are reading the property from it
        if (parent) {
            return parent.getProperty(key);
        }
        // otherwise we just read it from the root exports object
        return this.getProperty(key, this.getDefaultExportValue());
    }
    addProperty(key, value, parent = null) {
        if (key.includes(".")) {
            const parts = key.split(".");
            const name = parts.shift();
            let property = this.getProperty(name, parent);
            if (!property) {
                property = this.addProperty(name, {}, parent || this.getDefaultExportValue());
            }
            const _parent = property.getLastChild((child) => {
                return ts_morph_1.Node.isObjectLiteralExpression(child);
            });
            if (!_parent) {
                throw new Error(`Could not add property '${parts[0]}'.`);
            }
            return this.addProperty(parts.join("."), value, _parent);
        }
        if (parent) {
            return parent.addPropertyAssignment({
                name: key,
                initializer: this.createInitializer(value),
            });
        }
        return this.addProperty(key, value, this.getDefaultExportValue());
    }
    createInitializer(value) {
        if (typeof value === "string") {
            return `'${value}'`;
        }
        else if (typeof value === "number" || typeof value === "boolean") {
            return `${value}`;
        }
        return `{}`;
    }
    setInitializerValue(initializer, newValue) {
        if (ts_morph_1.Node.isStringLiteral(initializer)) {
            return initializer.setLiteralValue(newValue);
        }
        if (ts_morph_1.Node.isNumericLiteral(initializer)) {
            return initializer.setLiteralValue(newValue);
        }
        if (ts_morph_1.Node.isBooleanKeyword(initializer)) {
            return initializer.setLiteralValue(newValue);
        }
        if (ts_morph_1.Node.isIdentifier(initializer)) {
            return this.setIdentifierValue(initializer, newValue);
        }
        throw new Error("Unsupported value type: " + initializer.getKindName());
    }
    getInitializerValue(initializer) {
        if (ts_morph_1.Node.isStringLiteral(initializer)) {
            return initializer.getLiteralValue();
        }
        if (ts_morph_1.Node.isNumericLiteral(initializer)) {
            return initializer.getLiteralValue();
        }
        if (ts_morph_1.Node.isBooleanKeyword(initializer)) {
            return initializer.getLiteralValue();
        }
        if (ts_morph_1.Node.isIdentifier(initializer)) {
            return this.getIdentifierValue(initializer);
        }
        throw new Error("Unsupported value type: " + initializer.getKindName());
    }
    getIdentifierValue(identifier) {
        const decl = this.config.getVariableDeclarationOrThrow(identifier.getText());
        const initializer = decl.getInitializerOrThrow();
        return this.getInitializerValue(initializer);
    }
    setIdentifierValue(identifier, newValue) {
        const decl = this.config.getVariableDeclarationOrThrow(identifier.getText());
        const initializer = decl.getInitializerOrThrow();
        this.setInitializerValue(initializer, newValue);
    }
    getPropertyValue(objectProperty) {
        if (!objectProperty) {
            return undefined;
        }
        let initializer;
        if (objectProperty instanceof ts_morph_1.PropertyAssignment ||
            objectProperty instanceof ts_morph_1.ShorthandPropertyAssignment) {
            initializer = objectProperty.getInitializer();
        }
        else {
            throw new Error("getPropertyValue Unsupported value found: " +
                objectProperty.getKindName());
        }
        if (ts_morph_1.Node.isStringLiteral(initializer)) {
            return initializer.getLiteralValue();
        }
        if (ts_morph_1.Node.isNumericLiteral(initializer)) {
            return initializer.getLiteralValue();
        }
        if (ts_morph_1.Node.isBooleanKeyword(initializer)) {
            return initializer.getLiteralValue();
        }
        if (ts_morph_1.Node.isIdentifier(initializer)) {
            return this.getIdentifierValue(initializer);
        }
    }
    setPropertyValue(objectProperty, newValue) {
        let initializer;
        if (objectProperty instanceof ts_morph_1.PropertyAssignment ||
            objectProperty instanceof ts_morph_1.ShorthandPropertyAssignment) {
            initializer = objectProperty.getInitializer();
        }
        else {
            throw new Error("Unsupported value found.");
        }
        this.setInitializerValue(initializer, newValue);
    }
    /**
     * @internal
     */
    getFullText() {
        return this.config.getFullText();
    }
    /**
     * @internal
     */
    getValue(key) {
        return this.getPropertyValue(this.getProperty(key));
    }
    setValue(key, value) {
        const property = this.getProperty(key);
        if (!property) {
            // add new property
            this.addProperty(key, value);
        }
        else {
            this.setPropertyValue(property, value);
        }
        return this.getFullText();
    }
}
exports.ConfigTransformer = ConfigTransformer;
//# sourceMappingURL=config-transformer.js.map