"use strict";
// The MIT License (MIT)
//
// Copyright (c) 2021 Firebase
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
Object.defineProperty(exports, "__esModule", { value: true });
exports.ListParam = exports.BooleanParam = exports.FloatParam = exports.IntParam = exports.StringParam = exports.SecretParam = exports.Param = exports.CompareExpression = exports.TernaryExpression = exports.Expression = void 0;
/*
 * A CEL expression which can be evaluated during function deployment, and
 * resolved to a value of the generic type parameter: i.e, you can pass
 * an Expression<number> as the value of an option that normally accepts numbers.
 */
class Expression {
    // Returns the Expression's runtime value, based on the CLI's resolution of params.
    value() {
        throw new Error('Not implemented');
    }
    // Returns the Expression's representation as a braced CEL expression.
    toCEL() {
        return `{{ ${this.toString()} }}`;
    }
    toJSON() {
        return this.toString();
    }
}
exports.Expression = Expression;
function quoteIfString(literal) {
    // TODO(vsfan@): CEL's string escape semantics are slightly different than Javascript's, what do we do here?
    return typeof literal === 'string' ? `"${literal}"` : literal;
}
/**
 * A CEL expression corresponding to a ternary operator, e.g {{ cond ? ifTrue : ifFalse }}
 */
class TernaryExpression extends Expression {
    constructor(test, ifTrue, ifFalse) {
        super();
        this.test = test;
        this.ifTrue = ifTrue;
        this.ifFalse = ifFalse;
        this.ifTrue = ifTrue;
        this.ifFalse = ifFalse;
    }
    value() {
        return !!this.test.value ? this.ifTrue : this.ifFalse;
    }
    toString() {
        return `${this.test} ? ${quoteIfString(this.ifTrue)} : ${quoteIfString(this.ifFalse)}`;
    }
}
exports.TernaryExpression = TernaryExpression;
/**
 * A CEL expression that evaluates to boolean true or false based on a comparison
 * between the value of another expression and a literal of that same type.
 */
class CompareExpression extends Expression {
    constructor(cmp, lhs, rhs) {
        super();
        this.cmp = cmp;
        this.lhs = lhs;
        this.rhs = rhs;
    }
    value() {
        const left = this.lhs.value();
        switch (this.cmp) {
            case '==':
                return left === this.rhs;
            case '>':
                return left > this.rhs;
            case '>=':
                return left >= this.rhs;
            case '<':
                return left < this.rhs;
            case '<=':
                return left <= this.rhs;
            default:
                throw new Error('Unknown comparator ' + this.cmp);
        }
    }
    toString() {
        return `${this.lhs} ${this.cmp} ${quoteIfString(this.rhs)}`;
    }
    then(ifTrue, ifFalse) {
        return new TernaryExpression(this, ifTrue, ifFalse);
    }
}
exports.CompareExpression = CompareExpression;
class Param extends Expression {
    constructor(name, options = {}) {
        super();
        this.name = name;
        this.options = options;
    }
    value() {
        throw new Error('Not implemented');
    }
    cmp(cmp, rhs) {
        return new CompareExpression(cmp, this, rhs);
    }
    equals(rhs) {
        return this.cmp('==', rhs);
    }
    toString() {
        return `params.${this.name}`;
    }
    toSpec() {
        const out = {
            name: this.name,
            ...this.options,
            type: this.constructor.type,
        };
        return out;
    }
}
exports.Param = Param;
Param.type = 'string';
class SecretParam {
    constructor(name) {
        this.name = name;
    }
    value() {
        return process.env[this.name] || '';
    }
    toSpec() {
        return {
            type: 'secret',
            name: this.name,
        };
    }
}
exports.SecretParam = SecretParam;
SecretParam.type = 'secret';
class StringParam extends Param {
    value() {
        return process.env[this.name] || '';
    }
}
exports.StringParam = StringParam;
class IntParam extends Param {
    value() {
        return parseInt(process.env[this.name] || '0', 10) || 0;
    }
}
exports.IntParam = IntParam;
IntParam.type = 'int';
class FloatParam extends Param {
    value() {
        return parseFloat(process.env[this.name] || '0') || 0;
    }
}
exports.FloatParam = FloatParam;
FloatParam.type = 'float';
class BooleanParam extends Param {
    value() {
        return !!process.env[this.name];
    }
    then(ifTrue, ifFalse) {
        return new TernaryExpression(this, ifTrue, ifFalse);
    }
}
exports.BooleanParam = BooleanParam;
BooleanParam.type = 'boolean';
class ListParam extends Param {
    value() {
        throw new Error('Not implemented');
    }
    toSpec() {
        const out = {
            name: this.name,
            type: 'list',
            ...this.options,
        };
        if (this.options.default && this.options.default.length > 0) {
            out.default = this.options.default.join(',');
        }
        return out;
    }
}
exports.ListParam = ListParam;
ListParam.type = 'list';
