"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var graphql_1 = require("graphql");
var arrays_1 = require("../utils/arrays");
var graphql_2 = require("../utils/graphql");
var schema_1 = require("../changes/schema");
var type_1 = require("../changes/type");
var directive_1 = require("../changes/directive");
var enum_1 = require("./enum");
var union_1 = require("./union");
var input_1 = require("./input");
var object_1 = require("./object");
var interface_1 = require("./interface");
var directive_2 = require("./directive");
function diff(oldSchema, newSchema) {
    var changes = [];
    var types = diffTypes(oldSchema, newSchema);
    var directives = diffDirectives(oldSchema, newSchema);
    // Added and removed types
    changes.push.apply(changes, types.added.map(type_1.typeAdded));
    changes.push.apply(changes, types.removed.map(type_1.typeRemoved));
    // Added and removed directives
    changes.push.apply(changes, directives.added.map(directive_1.directiveAdded));
    changes.push.apply(changes, directives.removed.map(directive_1.directiveRemoved));
    // Changes in Schema
    changes.push.apply(changes, changesInSchema(oldSchema, newSchema));
    // Changes in Type
    types.common.forEach(function (_a) {
        var inOld = _a.inOld, inNew = _a.inNew;
        changes.push.apply(changes, changesInType(inOld, inNew));
    });
    // Changes in Directives
    directives.common.forEach(function (_a) {
        var inOld = _a.inOld, inNew = _a.inNew;
        changes.push.apply(changes, directive_2.changesInDirective(inOld, inNew));
    });
    return changes;
}
exports.diff = diff;
function diffTypes(oldSchema, newSchema) {
    var oldTypeMap = oldSchema.getTypeMap();
    var newTypeMap = newSchema.getTypeMap();
    var oldTypenames = Object.keys(oldTypeMap).filter(function (name) { return !graphql_2.isPrimitive(name); });
    var newTypenames = Object.keys(newTypeMap).filter(function (name) { return !graphql_2.isPrimitive(name); });
    var added = arrays_1.diffArrays(newTypenames, oldTypenames).map(function (name) { return newTypeMap[name]; });
    var removed = arrays_1.diffArrays(oldTypenames, newTypenames).map(function (name) { return oldTypeMap[name]; });
    var common = arrays_1.unionArrays(oldTypenames, newTypenames).map(function (name) { return ({
        inOld: oldTypeMap[name],
        inNew: newTypeMap[name],
    }); });
    return {
        added: added,
        removed: removed,
        common: common,
    };
}
function diffDirectives(oldSchema, newSchema) {
    var oldDirectives = oldSchema.getDirectives();
    var newDirectives = newSchema.getDirectives();
    var oldNames = oldDirectives.map(function (d) { return d.name; });
    var newNames = newDirectives.map(function (d) { return d.name; });
    var added = arrays_1.diffArrays(newNames, oldNames).map(function (name) {
        return newDirectives.find(function (d) { return d.name === name; });
    });
    var removed = arrays_1.diffArrays(oldNames, newNames).map(function (name) {
        return oldDirectives.find(function (d) { return d.name === name; });
    });
    var common = arrays_1.unionArrays(oldNames, newNames).map(function (name) { return ({
        inOld: oldDirectives.find(function (d) { return d.name === name; }),
        inNew: newDirectives.find(function (d) { return d.name === name; }),
    }); });
    return {
        added: added,
        removed: removed,
        common: common,
    };
}
function changesInSchema(oldSchema, newSchema) {
    var changes = [];
    var oldRoot = {
        query: (oldSchema.getQueryType() || {}).name,
        mutation: (oldSchema.getMutationType() || {}).name,
        subscription: (oldSchema.getSubscriptionType() || {})
            .name,
    };
    var newRoot = {
        query: (newSchema.getQueryType() || {}).name,
        mutation: (newSchema.getMutationType() || {}).name,
        subscription: (newSchema.getSubscriptionType() || {})
            .name,
    };
    if (oldRoot.query !== newRoot.query) {
        changes.push(schema_1.schemaQueryTypeChanged(oldSchema, newSchema));
    }
    if (oldRoot.mutation !== newRoot.mutation) {
        changes.push(schema_1.schemaMutationTypeChanged(oldSchema, newSchema));
    }
    if (oldRoot.subscription !== newRoot.subscription) {
        changes.push(schema_1.schemaSubscriptionTypeChanged(oldSchema, newSchema));
    }
    return changes;
}
function changesInType(oldType, newType) {
    var changes = [];
    if (graphql_1.isEnumType(oldType) && graphql_1.isEnumType(newType)) {
        changes = enum_1.changesInEnum(oldType, newType);
    }
    else if (graphql_1.isUnionType(oldType) && graphql_1.isUnionType(newType)) {
        changes = union_1.changesInUnion(oldType, newType);
    }
    else if (graphql_1.isInputObjectType(oldType) && graphql_1.isInputObjectType(newType)) {
        changes = input_1.changesInInputObject(oldType, newType);
    }
    else if (graphql_1.isObjectType(oldType) && graphql_1.isObjectType(newType)) {
        changes = object_1.changesInObject(oldType, newType);
    }
    else if (graphql_1.isInterfaceType(oldType) && graphql_1.isInterfaceType(newType)) {
        changes = interface_1.changesInInterface(oldType, newType);
    }
    else {
        changes = [type_1.typeKindChanged(oldType, newType)];
    }
    if (oldType.description !== newType.description) {
        changes.push(type_1.typeDescriptionChanged(oldType, newType));
    }
    return changes;
}
//# sourceMappingURL=schema.js.map