"use strict";
/*
 * @adonisjs/validator
 *
 * (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.LiteralCompiler = void 0;
/**
 * Exposes the API to compile the literal node to a set of inline
 * Javascript instructions.
 */
class LiteralCompiler {
    constructor(field, node, compiler, references) {
        this.field = field;
        this.node = node;
        this.compiler = compiler;
        this.references = references;
        this.disableOutVariable = false;
        this.forceValueDeclaration = false;
    }
    /**
     * Initiate the variable name that hold the value of the current
     * field
     */
    initiateVariableName() {
        this.variableName = this.variableName || `val_${this.compiler.referenceVariableCounter++}`;
    }
    /**
     * Writes the compiled statement to declare the value variable
     */
    declareValueVariable(buffer) {
        const referenceExpression = this.compiler.pointerToExpression(this.field);
        buffer.writeComment(`Validate ${this.references.referenceVariable}[${referenceExpression}]`);
        buffer.writeExpression(`let ${this.variableName} = ${this.references.referenceVariable}[${referenceExpression}]`);
    }
    declareExistsVariable(buffer) {
        buffer.writeExpression(this.compiler.getVariableExistsDeclaration(this.variableName), true);
    }
    /**
     * Writes the compiled statement for the mutation function. The mutate function is
     * passed to the validation definition.
     */
    declareMutationFunction(buffer) {
        buffer.writeStatement(this.compiler.getMutationFnDeclararationExpression(this.variableName), true);
    }
    /**
     * Writes the compiled statement to declare the options that are passed to all
     * the validation functions for this field.
     */
    declareValidationOptions(buffer) {
        const pointerExpressions = this.references.parentPointer.concat(this.field);
        const pointerExpression = this.compiler.pointersToExpression(pointerExpressions);
        let ar;
        const hasDynamicPointers = pointerExpressions.find(({ type }) => type === 'identifier');
        if (hasDynamicPointers) {
            ar = this.compiler.pointersToExpression(pointerExpressions.map(({ name, type }) => {
                return type === 'identifier' ? { name: '*', type: 'literal' } : { name, type };
            }));
        }
        buffer.writeExpression(this.compiler.getOptionsDeclarationExpression(this.variableName, this.compiler.pointerToExpression(this.field), this.references.referenceVariable, pointerExpression, ar), true);
    }
    /**
     * Writes the compiled statement to assign the out value.
     */
    assignOutValue(buffer) {
        const referenceVariable = this.compiler.pointerToExpression(this.field);
        buffer.writeStatement(`if (${this.compiler.getVariableExistsName(this.variableName)}${this.node.nullable ? ` || ${this.variableName} === null` : ''}) {`);
        buffer.indent();
        buffer.writeExpression(`${this.references.outVariable}[${referenceVariable}] = ${this.variableName}`);
        buffer.dedent();
        buffer.writeStatement('}');
    }
    /**
     * Converts the literal node to compiled Javascript statement.
     */
    compile(buffer) {
        /**
         * Return early when no validation rules are defined on the node. However, we check
         * for `forceValueDeclaration` flag to see if we should declare the value
         * variable or not
         */
        if (!this.node.rules.length) {
            if (this.forceValueDeclaration) {
                this.initiateVariableName();
                this.declareValueVariable(buffer);
                this.declareExistsVariable(buffer);
            }
            return;
        }
        /**
         * Define variable name
         */
        this.initiateVariableName();
        this.declareValueVariable(buffer);
        /**
         * Define variable to know if value is undefined or null
         */
        this.declareExistsVariable(buffer);
        /**
         * Define mutation function
         */
        this.declareMutationFunction(buffer);
        /**
         * Define options
         */
        this.declareValidationOptions(buffer);
        /**
         * Write expressions for each validation call for the defined
         * rules
         */
        this.node.rules.forEach((rule) => {
            buffer.writeExpression(this.compiler.getValidationCallableExpression(this.variableName, rule));
        });
        /**
         * Do not define the out variable when disabled
         */
        if (!this.disableOutVariable) {
            this.assignOutValue(buffer);
        }
    }
}
exports.LiteralCompiler = LiteralCompiler;
