"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.extractPackageFile = void 0;
const good_enough_parser_1 = require("good-enough-parser");
const logger_1 = require("../../../logger");
const regex_1 = require("../../../util/regex");
const url_1 = require("../../../util/url");
const maven_1 = require("../../datasource/maven");
const sbt_package_1 = require("../../datasource/sbt-package");
const sbt_plugin_1 = require("../../datasource/sbt-plugin");
const common_1 = require("../gradle/common");
const util_1 = require("./util");
const scala = good_enough_parser_1.lang.createLang('scala');
const scalaVersionMatch = good_enough_parser_1.query
    .sym('scalaVersion')
    .op(':=')
    .alt(good_enough_parser_1.query.str((ctx, { value: scalaVersion }) => ({ ...ctx, scalaVersion })), good_enough_parser_1.query.sym((ctx, { value: varName }) => {
    const scalaVersion = ctx.vars[varName];
    if (scalaVersion) {
        ctx.scalaVersion = scalaVersion;
    }
    return ctx;
}))
    .handler((ctx) => {
    if (ctx.scalaVersion) {
        const dep = {
            datasource: maven_1.MavenDatasource.id,
            depName: 'scala',
            packageName: 'org.scala-lang:scala-library',
            currentValue: ctx.scalaVersion,
            separateMinorPatch: true,
        };
        ctx.scalaVersion = (0, util_1.normalizeScalaVersion)(ctx.scalaVersion);
        ctx.deps.push(dep);
    }
    return ctx;
});
const packageFileVersionMatch = good_enough_parser_1.query
    .sym('version')
    .op(':=')
    .alt(good_enough_parser_1.query.str((ctx, { value: packageFileVersion }) => ({
    ...ctx,
    packageFileVersion,
})), good_enough_parser_1.query.sym((ctx, { value: varName }) => {
    const packageFileVersion = ctx.vars[varName];
    if (packageFileVersion) {
        ctx.packageFileVersion = packageFileVersion;
    }
    return ctx;
}));
const variableNameMatch = good_enough_parser_1.query.sym((ctx, { value: varName }) => ({
    ...ctx,
    currentVarName: varName,
}));
const variableValueMatch = good_enough_parser_1.query.str((ctx, { value }) => {
    ctx.vars[ctx.currentVarName] = value;
    delete ctx.currentVarName;
    return ctx;
});
const assignmentMatch = good_enough_parser_1.query.sym('val').join(variableNameMatch).op('=');
const variableDefinitionMatch = good_enough_parser_1.query
    .alt(good_enough_parser_1.query.sym('lazy').join(assignmentMatch), assignmentMatch, variableNameMatch.op(':='))
    .join(variableValueMatch);
const groupIdMatch = good_enough_parser_1.query.alt(good_enough_parser_1.query.sym((ctx, { value: varName }) => {
    const currentGroupId = ctx.vars[varName];
    if (currentGroupId) {
        ctx.groupId = currentGroupId;
    }
    return ctx;
}), good_enough_parser_1.query.str((ctx, { value: groupId }) => ({ ...ctx, groupId })));
const artifactIdMatch = good_enough_parser_1.query.alt(good_enough_parser_1.query.sym((ctx, { value: varName }) => {
    const artifactId = ctx.vars[varName];
    if (artifactId) {
        ctx.artifactId = artifactId;
    }
    return ctx;
}), good_enough_parser_1.query.str((ctx, { value: artifactId }) => ({ ...ctx, artifactId })));
const versionMatch = good_enough_parser_1.query.alt(good_enough_parser_1.query.sym((ctx, { value: varName }) => {
    const currentValue = ctx.vars[varName];
    if (currentValue) {
        ctx.currentValue = currentValue;
        ctx.groupName = varName;
    }
    return ctx;
}), good_enough_parser_1.query.str((ctx, { value: currentValue }) => ({ ...ctx, currentValue })));
const simpleDependencyMatch = groupIdMatch
    .op('%')
    .join(artifactIdMatch)
    .op('%')
    .join(versionMatch);
const versionedDependencyMatch = groupIdMatch
    .op('%%')
    .join(artifactIdMatch)
    .handler((ctx) => ({ ...ctx, useScalaVersion: true }))
    .op('%')
    .join(versionMatch);
function depHandler(ctx) {
    const { scalaVersion, groupId, artifactId, currentValue, useScalaVersion, depType, groupName, } = ctx;
    delete ctx.groupId;
    delete ctx.artifactId;
    delete ctx.currentValue;
    delete ctx.useScalaVersion;
    delete ctx.depType;
    delete ctx.groupName;
    const depName = `${groupId}:${artifactId}`;
    const dep = {
        datasource: sbt_package_1.SbtPackageDatasource.id,
        depName,
        packageName: scalaVersion && useScalaVersion ? `${depName}_${scalaVersion}` : depName,
        currentValue,
    };
    if (depType) {
        dep.depType = depType;
    }
    if (depType === 'plugin') {
        dep.datasource = sbt_plugin_1.SbtPluginDatasource.id;
    }
    if (groupName) {
        dep.groupName = groupName;
    }
    ctx.deps.push(dep);
    return ctx;
}
function depTypeHandler(ctx, { value: depType }) {
    return { ...ctx, depType };
}
const sbtPackageMatch = good_enough_parser_1.query
    .opt(good_enough_parser_1.query.opt(good_enough_parser_1.query.sym('lazy')).sym('val').sym().op('='))
    .alt(simpleDependencyMatch, versionedDependencyMatch)
    .opt(good_enough_parser_1.query.alt(good_enough_parser_1.query.sym('classifier').str(depTypeHandler), good_enough_parser_1.query.op('%').sym(depTypeHandler), good_enough_parser_1.query.op('%').str(depTypeHandler)))
    .handler(depHandler);
const sbtPluginMatch = good_enough_parser_1.query
    .sym((0, regex_1.regEx)(/^(?:addSbtPlugin|addCompilerPlugin)$/))
    .tree({
    type: 'wrapped-tree',
    maxDepth: 1,
    search: good_enough_parser_1.query
        .begin()
        .alt(simpleDependencyMatch, versionedDependencyMatch)
        .end(),
})
    .handler((ctx) => ({ ...ctx, depType: 'plugin' }))
    .handler(depHandler);
const resolverMatch = good_enough_parser_1.query
    .str()
    .sym('at')
    .str((ctx, { value }) => {
    if ((0, url_1.parseUrl)(value)) {
        ctx.registryUrls.push(value);
    }
    return ctx;
});
const addResolverMatch = good_enough_parser_1.query.sym('resolvers').alt(good_enough_parser_1.query.op('+=').join(resolverMatch), good_enough_parser_1.query.op('++=').sym('Seq').tree({
    type: 'wrapped-tree',
    maxDepth: 1,
    search: resolverMatch,
}));
function registryUrlHandler(ctx) {
    for (const dep of ctx.deps) {
        dep.registryUrls = [...ctx.registryUrls];
        if (dep.depType === 'plugin') {
            dep.registryUrls.push(sbt_plugin_1.SBT_PLUGINS_REPO);
        }
    }
    return ctx;
}
const query = good_enough_parser_1.query.tree({
    type: 'root-tree',
    maxDepth: 32,
    search: good_enough_parser_1.query.alt(scalaVersionMatch, packageFileVersionMatch, sbtPackageMatch, sbtPluginMatch, addResolverMatch, variableDefinitionMatch),
    postHandler: registryUrlHandler,
});
function extractPackageFile(content, _packageFile) {
    let parsedResult = null;
    try {
        parsedResult = scala.query(content, query, {
            vars: {},
            deps: [],
            registryUrls: [common_1.MAVEN_REPO],
        });
    }
    catch (err) /* istanbul ignore next */ {
        logger_1.logger.warn({ err }, 'Sbt parsing error');
    }
    if (!parsedResult) {
        return null;
    }
    const { deps, packageFileVersion } = parsedResult;
    if (!deps.length) {
        return null;
    }
    return { deps, packageFileVersion };
}
exports.extractPackageFile = extractPackageFile;
//# sourceMappingURL=extract.js.map