/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Red Hat, Inc. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
(function (factory) {
    if (typeof module === "object" && typeof module.exports === "object") {
        var v = factory(require, exports);
        if (v !== undefined) module.exports = v;
    }
    else if (typeof define === "function" && define.amd) {
        define(["require", "exports", "yaml", "./jsonParser07"], factory);
    }
})(function (require, exports) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.toOffsetLength = exports.convertAST = void 0;
    const yaml_1 = require("yaml");
    const jsonParser07_1 = require("./jsonParser07");
    const maxRefCount = 1000;
    let refDepth = 0;
    function convertAST(parent, node, doc, lineCounter) {
        if (!parent) {
            // first invocation
            refDepth = 0;
        }
        if (!node) {
            return null;
        }
        if ((0, yaml_1.isMap)(node)) {
            return convertMap(node, parent, doc, lineCounter);
        }
        if ((0, yaml_1.isPair)(node)) {
            return convertPair(node, parent, doc, lineCounter);
        }
        if ((0, yaml_1.isSeq)(node)) {
            return convertSeq(node, parent, doc, lineCounter);
        }
        if ((0, yaml_1.isScalar)(node)) {
            return convertScalar(node, parent);
        }
        if ((0, yaml_1.isAlias)(node)) {
            if (refDepth > maxRefCount) {
                // document contains excessive aliasing
                return;
            }
            return convertAlias(node, parent, doc, lineCounter);
        }
    }
    exports.convertAST = convertAST;
    function convertMap(node, parent, doc, lineCounter) {
        let range;
        if (node.flow && !node.range) {
            range = collectFlowMapRange(node);
        }
        else {
            range = node.range;
        }
        const result = new jsonParser07_1.ObjectASTNodeImpl(parent, node, ...toFixedOffsetLength(range, lineCounter));
        for (const it of node.items) {
            if ((0, yaml_1.isPair)(it)) {
                result.properties.push(convertAST(result, it, doc, lineCounter));
            }
        }
        return result;
    }
    function convertPair(node, parent, doc, lineCounter) {
        const keyNode = node.key;
        const valueNode = node.value;
        const rangeStart = keyNode.range[0];
        let rangeEnd = keyNode.range[1];
        let nodeEnd = keyNode.range[2];
        if (valueNode) {
            rangeEnd = valueNode.range[1];
            nodeEnd = valueNode.range[2];
        }
        // Pair does not return a range using the key/value ranges to fake one.
        const result = new jsonParser07_1.PropertyASTNodeImpl(parent, node, ...toFixedOffsetLength([rangeStart, rangeEnd, nodeEnd], lineCounter));
        if ((0, yaml_1.isAlias)(keyNode)) {
            const keyAlias = new jsonParser07_1.StringASTNodeImpl(parent, keyNode, ...toOffsetLength(keyNode.range));
            keyAlias.value = keyNode.source;
            result.keyNode = keyAlias;
        }
        else {
            result.keyNode = convertAST(result, keyNode, doc, lineCounter);
        }
        result.valueNode = convertAST(result, valueNode, doc, lineCounter);
        return result;
    }
    function convertSeq(node, parent, doc, lineCounter) {
        const result = new jsonParser07_1.ArrayASTNodeImpl(parent, node, ...toOffsetLength(node.range));
        for (const it of node.items) {
            if ((0, yaml_1.isNode)(it)) {
                const convertedNode = convertAST(result, it, doc, lineCounter);
                // due to recursion protection, convertAST may return undefined
                if (convertedNode) {
                    result.children.push(convertedNode);
                }
            }
        }
        return result;
    }
    function convertScalar(node, parent) {
        if (node.value === null) {
            return new jsonParser07_1.NullASTNodeImpl(parent, node, ...toOffsetLength(node.range));
        }
        switch (typeof node.value) {
            case 'string': {
                const result = new jsonParser07_1.StringASTNodeImpl(parent, node, ...toOffsetLength(node.range));
                result.value = node.value;
                return result;
            }
            case 'boolean':
                return new jsonParser07_1.BooleanASTNodeImpl(parent, node, node.value, ...toOffsetLength(node.range));
            case 'number': {
                const result = new jsonParser07_1.NumberASTNodeImpl(parent, node, ...toOffsetLength(node.range));
                result.value = node.value;
                result.isInteger = Number.isInteger(result.value);
                return result;
            }
            default: {
                // fail safe converting, we need to return some node anyway
                const result = new jsonParser07_1.StringASTNodeImpl(parent, node, ...toOffsetLength(node.range));
                result.value = node.source;
                return result;
            }
        }
    }
    function convertAlias(node, parent, doc, lineCounter) {
        refDepth++;
        const resolvedNode = node.resolve(doc);
        if (resolvedNode) {
            return convertAST(parent, resolvedNode, doc, lineCounter);
        }
        else {
            const resultNode = new jsonParser07_1.StringASTNodeImpl(parent, node, ...toOffsetLength(node.range));
            resultNode.value = node.source;
            return resultNode;
        }
    }
    function toOffsetLength(range) {
        return [range[0], range[1] - range[0]];
    }
    exports.toOffsetLength = toOffsetLength;
    /**
     * Convert offsets to offset+length with fix length to not include '\n' character in some cases
     * @param range the yaml ast range
     * @param lineCounter the line counter
     * @returns the offset and length
     */
    function toFixedOffsetLength(range, lineCounter) {
        const start = lineCounter.linePos(range[0]);
        const end = lineCounter.linePos(range[1]);
        const result = [range[0], range[1] - range[0]];
        // -1 as range may include '\n'
        if (start.line !== end.line && (lineCounter.lineStarts.length !== end.line || end.col === 1)) {
            result[1]--;
        }
        return result;
    }
    function collectFlowMapRange(node) {
        let start = Number.MAX_SAFE_INTEGER;
        let end = 0;
        for (const it of node.items) {
            if ((0, yaml_1.isPair)(it)) {
                if ((0, yaml_1.isNode)(it.key)) {
                    if (it.key.range && it.key.range[0] <= start) {
                        start = it.key.range[0];
                    }
                }
                if ((0, yaml_1.isNode)(it.value)) {
                    if (it.value.range && it.value.range[2] >= end) {
                        end = it.value.range[2];
                    }
                }
            }
        }
        return [start, end, end];
    }
});
//# sourceMappingURL=ast-converter.js.map