/**
 * Facilities for interpreting the patterns passed in dochtml in
 * metadata files.
 *
 * @author Louis-Dominique Dubeau
 * @license MPL 2.0
 * @copyright Mangalam Research Center for Buddhist Languages
 */
define(["require", "exports"], function (require, exports) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    /**
     * A literal value in a pattern.
     */
    class Literal {
        /**
         * @param value The value to which this literal resolves to.
         */
        constructor(value) {
            this.value = value;
        }
        execute() {
            return this.value;
        }
    }
    /**
     * A concatenation operation.
     */
    class Concat {
        /**
         * @param values The patterns to concatenate.
         */
        constructor(values) {
            this.values = values;
        }
        execute(context) {
            return this.values.map((value) => value.execute(context)).join("");
        }
    }
    /**
     * An interpolation like ``${foo}``.
     */
    class Interpolation {
        /**
         * @param name The name to interpolate.
         */
        constructor(name) {
            this.name = name;
        }
        execute(context) {
            return context.resolveName(this.name);
        }
    }
    /**
     * A substitution operation, like in ``${foo:s("a","b")}``.
     */
    class Substitution {
        constructor(pattern, substitution, child) {
            this.pattern = pattern;
            this.substitution = substitution;
            this.child = child;
        }
        execute(context) {
            const value = this.child.execute(context);
            return value.replace(this.pattern, this.substitution);
        }
    }
    /**
     * Compile a string pattern to a [[DocPattern]] object.
     *
     * @param pattern The pattern to compile.
     *
     * @returns The compiled pattern.
     */
    function compile(pattern) {
        const parts = pattern.split(/(\$\{|\})/);
        const patterns = [];
        let interpolating = false;
        for (const part of parts) {
            // tslint:disable-next-line:no-invalid-template-strings
            if (part === "${") {
                if (interpolating) {
                    throw new Error("nested interpolations are invalid");
                }
                interpolating = true;
            }
            else if (part === "}") {
                if (!interpolating) {
                    throw new Error("errant interpolation closure");
                }
                interpolating = false;
            }
            else if (interpolating) {
                const [name, transform] = part.split(":", 1);
                if (transform === undefined) {
                    patterns.push(new Interpolation(name));
                }
                else {
                    if (transform[0] === "s") {
                        const paramList = transform.slice(1);
                        if (paramList[0] !== "(" || paramList[paramList.length - 1] !== ")") {
                            throw new Error("transform parameters must be in parentheses");
                        }
                        // We slice to drop the parentheses.
                        let params = paramList.slice(1, -1).split(",").map((x) => x.trim());
                        if (params.length !== 2) {
                            throw new Error("an s transform takes 2 parameters");
                        }
                        for (const param of params) {
                            if (param[0] !== "\"" || param[param.length - 1] !== "\"") {
                                throw new Error(`parameter must be a string wrapped in double \
quotes: ${param}`);
                            }
                        }
                        // Drop the wrapping quotes.
                        params = params.map((x) => x.slice(1, -1));
                        patterns.push(new Substitution(params[0], params[1], new Interpolation(name)));
                    }
                    else {
                        throw new Error(`unknown transform ${transform}`);
                    }
                }
            }
            else {
                patterns.push(new Literal(part));
            }
        }
        if (interpolating) {
            throw new Error("an interpolation was not closed");
        }
        return new Concat(patterns);
    }
    exports.compile = compile;
});
//  LocalWords:  dochtml MPL unresolvable param
//# sourceMappingURL=doc-pattern.js.map