"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tokens_1 = require("../core/tokens");
const cloudformation_token_1 = require("./cloudformation-token");
/**
 * Class for JSON routines that are framework-aware
 */
class CloudFormationJSON {
    /**
     * Turn an arbitrary structure potentially containing Tokens into a JSON string.
     *
     * Returns a Token which will evaluate to CloudFormation expression that
     * will be evaluated by CloudFormation to the JSON representation of the
     * input structure.
     *
     * All Tokens substituted in this way must return strings, or the evaluation
     * in CloudFormation will fail.
     */
    static stringify(obj) {
        return new tokens_1.Token(() => {
            // Resolve inner value first so that if they evaluate to literals, we
            // maintain the type (and discard 'undefined's).
            //
            // Then replace intrinsics with a special subclass of Token that
            // overrides toJSON() to the marker string, so if we resolve() the
            // strings again it evaluates to the right string. It also
            // deep-escapes any strings inside the intrinsic, so that if literal
            // strings are used in {Fn::Join} or something, they will end up
            // escaped in the final JSON output.
            const resolved = tokens_1.resolve(obj);
            // We can just directly return this value, since resolve() will be called
            // on our return value anyway.
            return JSON.stringify(deepReplaceIntrinsics(resolved));
        });
        /**
         * Recurse into a structure, replace all intrinsics with IntrinsicTokens.
         */
        function deepReplaceIntrinsics(x) {
            if (cloudformation_token_1.isIntrinsic(x)) {
                return wrapIntrinsic(x);
            }
            if (Array.isArray(x)) {
                return x.map(deepReplaceIntrinsics);
            }
            if (typeof x === 'object') {
                for (const key of Object.keys(x)) {
                    x[key] = deepReplaceIntrinsics(x[key]);
                }
            }
            return x;
        }
        function wrapIntrinsic(intrinsic) {
            return new IntrinsicToken(() => deepQuoteStringsForJSON(intrinsic));
        }
    }
}
exports.CloudFormationJSON = CloudFormationJSON;
/**
 * Token that also stringifies in the toJSON() operation.
 */
class IntrinsicToken extends cloudformation_token_1.CloudFormationToken {
    /**
     * Special handler that gets called when JSON.stringify() is used.
     */
    toJSON() {
        return this.toString();
    }
}
/**
 * Deep escape strings for use in a JSON context
 */
function deepQuoteStringsForJSON(x) {
    if (typeof x === 'string') {
        // Whenever we escape a string we strip off the outermost quotes
        // since we're already in a quoted context.
        const stringified = JSON.stringify(x);
        return stringified.substring(1, stringified.length - 1);
    }
    if (Array.isArray(x)) {
        return x.map(deepQuoteStringsForJSON);
    }
    if (typeof x === 'object') {
        for (const key of Object.keys(x)) {
            x[key] = deepQuoteStringsForJSON(x[key]);
        }
    }
    return x;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xvdWRmb3JtYXRpb24tanNvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImNsb3VkZm9ybWF0aW9uLWpzb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSwyQ0FBZ0Q7QUFDaEQsaUVBQTBFO0FBRTFFOztHQUVHO0FBQ0gsTUFBYSxrQkFBa0I7SUFDM0I7Ozs7Ozs7OztPQVNHO0lBQ0ksTUFBTSxDQUFDLFNBQVMsQ0FBQyxHQUFRO1FBQzVCLE9BQU8sSUFBSSxjQUFLLENBQUMsR0FBRyxFQUFFO1lBQ2xCLHFFQUFxRTtZQUNyRSxnREFBZ0Q7WUFDaEQsRUFBRTtZQUNGLGdFQUFnRTtZQUNoRSxrRUFBa0U7WUFDbEUsMERBQTBEO1lBQzFELG9FQUFvRTtZQUNwRSxnRUFBZ0U7WUFDaEUsb0NBQW9DO1lBQ3BDLE1BQU0sUUFBUSxHQUFHLGdCQUFPLENBQUMsR0FBRyxDQUFDLENBQUM7WUFFOUIseUVBQXlFO1lBQ3pFLDhCQUE4QjtZQUM5QixPQUFPLElBQUksQ0FBQyxTQUFTLENBQUMscUJBQXFCLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQztRQUMzRCxDQUFDLENBQUMsQ0FBQztRQUVIOztXQUVHO1FBQ0gsU0FBUyxxQkFBcUIsQ0FBQyxDQUFNO1lBQ2pDLElBQUksa0NBQVcsQ0FBQyxDQUFDLENBQUMsRUFBRTtnQkFDaEIsT0FBTyxhQUFhLENBQUMsQ0FBQyxDQUFDLENBQUM7YUFDM0I7WUFFRCxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUU7Z0JBQ2xCLE9BQU8sQ0FBQyxDQUFDLEdBQUcsQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDO2FBQ3ZDO1lBRUQsSUFBSSxPQUFPLENBQUMsS0FBSyxRQUFRLEVBQUU7Z0JBQ3ZCLEtBQUssTUFBTSxHQUFHLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRTtvQkFDOUIsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxHQUFHLHFCQUFxQixDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO2lCQUMxQzthQUNKO1lBRUQsT0FBTyxDQUFDLENBQUM7UUFDYixDQUFDO1FBRUQsU0FBUyxhQUFhLENBQUMsU0FBYztZQUNqQyxPQUFPLElBQUksY0FBYyxDQUFDLEdBQUcsRUFBRSxDQUFDLHVCQUF1QixDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUM7UUFDeEUsQ0FBQztJQUNMLENBQUM7Q0FDSjtBQXRERCxnREFzREM7QUFFRDs7R0FFRztBQUNILE1BQU0sY0FBZSxTQUFRLDBDQUFtQjtJQUM1Qzs7T0FFRztJQUNJLE1BQU07UUFDVCxPQUFPLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztJQUMzQixDQUFDO0NBQ0o7QUFFRDs7R0FFRztBQUNILFNBQVMsdUJBQXVCLENBQUMsQ0FBTTtJQUNuQyxJQUFJLE9BQU8sQ0FBQyxLQUFLLFFBQVEsRUFBRTtRQUN2QixnRUFBZ0U7UUFDaEUsMkNBQTJDO1FBQzNDLE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDdEMsT0FBTyxXQUFXLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBRSxXQUFXLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDO0tBQzNEO0lBRUQsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFO1FBQ2xCLE9BQU8sQ0FBQyxDQUFDLEdBQUcsQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDO0tBQ3pDO0lBRUQsSUFBSSxPQUFPLENBQUMsS0FBSyxRQUFRLEVBQUU7UUFDdkIsS0FBSyxNQUFNLEdBQUcsSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFO1lBQzlCLENBQUMsQ0FBQyxHQUFHLENBQUMsR0FBRyx1QkFBdUIsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztTQUM1QztLQUNKO0lBRUQsT0FBTyxDQUFDLENBQUM7QUFDYixDQUFDIn0=