module.exports = function (defs) {
    var used = [];
    var usedResult = [];
    var fork = {};

    function use(plugin) {
        var idx = used.indexOf(plugin);
        if (idx === -1) {
            idx = used.length;
            used.push(plugin);
            usedResult[idx] = plugin(fork);
        }
        return usedResult[idx];
    }

    fork.use = use;

    var types = use(require('./lib/types'));

    defs.forEach(use);

    types.finalize();

    var exports = {
        Type: types.Type,
        builtInTypes: types.builtInTypes,
        namedTypes: types.namedTypes,
        builders: types.builders,
        defineMethod: types.defineMethod,
        getFieldNames: types.getFieldNames,
        getFieldValue: types.getFieldValue,
        eachField: types.eachField,
        someField: types.someField,
        getSupertypeNames: types.getSupertypeNames,
        astNodesAreEquivalent: use(require("./lib/equiv")),
        finalize: types.finalize,
        Path: use(require('./lib/path')),
        NodePath: use(require("./lib/node-path")),
        PathVisitor: use(require("./lib/path-visitor")),
        use: use
    };

    exports.visit = exports.PathVisitor.visit;

    return exports;
};