"use strict";
/*
 * Copyright © 2020 Atomist, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.DockerFileParser = void 0;
const logger_1 = require("@atomist/automation-client/lib/util/logger");
const dockerfile_ast_1 = require("dockerfile-ast");
class DockerFileParserClass {
    async toAst(f) {
        try {
            const dockerfile = dockerfile_ast_1.DockerfileParser.parse(await f.getContent());
            const doc = dockerfile.document;
            const $children = dockerfile.getInstructions().map(i => instructionToTreeNode(i, doc));
            return {
                $name: f.name,
                $children,
            };
        }
        catch (err) {
            logger_1.logger.error("Error parsing Dockerfile", err);
            throw err;
        }
    }
}
/**
 * FileParser instance to use for Docker files.
 * Example path expressions, given "node:argon" as the image
 *  //FROM/image/name - returns a node with the value "node" etc
 *  //FROM/image/tag - returns a node with the value "argon" etc
 * @type {DockerFileParserClass}
 */
exports.DockerFileParser = new DockerFileParserClass();
function instructionToTreeNode(l, doc, parent) {
    const n = {
        $name: l.getKeyword(),
        $value: l.getTextContent(),
        $parent: parent,
        $offset: l.getRange() ? convertToOffset(l.getRange().start, doc) : undefined,
    };
    // Deconstruct subelements. There is no generic tree structure in the
    // AST library, so we need to do this manually for subelements we care about.
    if (isFrom(l)) {
        addChildrenFromFromStructure(n, l, doc);
    }
    else if (isLabel(l)) {
        addChildrenFromLabelStructure(n, l, doc);
    }
    else {
        switch (l.getKeyword()) {
            case "MAINTAINER":
                addChildrenFromMaintainer(n, l, doc);
                break;
            case "EXPOSE":
                n.$children = [
                    {
                        $name: "port",
                        $value: l.getArgumentsContent(),
                    },
                ];
                break;
            default:
                break;
        }
    }
    return n;
}
function isFrom(l) {
    const maybe = l;
    return !!maybe.getImageName;
}
function isLabel(l) {
    const maybe = l;
    return !!maybe.getProperties;
}
// Deconstruct FROM to add children.
// We need to do this for all structures we want to see inside
function addChildrenFromFromStructure(n, l, doc) {
    const nameChild = {
        $name: "name",
        $value: l.getImageName(),
        $offset: convertToOffset(l.getImageNameRange().start, doc),
    };
    const $children = [nameChild];
    if (!!l.getImageTag()) {
        $children.push({
            $name: "tag",
            $value: l.getImageTag(),
            $offset: convertToOffset(l.getImageTagRange().start, doc),
        });
    }
    n.$children = [
        {
            $parent: n,
            $name: "image",
            $value: l.getImage(),
            $offset: convertToOffset(l.getImageRange().start, doc),
            $children,
        },
    ];
}
function addChildrenFromLabelStructure(n, l, doc) {
    n.$children = l.getProperties().map(prop => ({
        $parent: n,
        $name: "pair",
        $value: l.getTextContent().slice("LABEL ".length),
        // Children are the name and value
        $children: [
            {
                $name: "key",
                $value: prop.getName(),
                $offset: convertToOffset(prop.getNameRange().start, doc),
            },
            {
                $name: "value",
                $value: prop.getValue(),
                $offset: prop.getValueRange() ? convertToOffset(prop.getValueRange().start, doc) : undefined,
            },
        ],
    }));
}
function addChildrenFromMaintainer(n, m, doc) {
    const rest = n.$value.slice("MAINTAINER ".length);
    n.$children = [
        {
            $parent: n,
            $name: "maintainer",
            $value: rest,
            $offset: n.$offset + "MAINTAINER ".length,
            $children: [],
        },
    ];
}
// Convert a position to an offset, given the document
function convertToOffset(pos, doc) {
    return doc.offsetAt(pos);
}
//# sourceMappingURL=DockerFileParser.js.map