/**
 * Object interface for registering suites
 *
 * Suites are described using objects. The object structure is a subset of suite properties, specifically name, the
 * lifecycle methods, and tests.
 *
 *     registerSuite('foo', {
 *         before() {},
 *         afterEach() {},
 *         tests: {
 *             bar() {},
 *             baz() {}
 *         }
 *     });
 *
 * Tests may also describe sub-suites:
 *
 *     registerSuite('foo', {
 *         tests: {
 *             fooStuff {
 *                 tests: {
 *                     bar() {},
 *                     baz() {}
 *                 }
 *             }
 *         }
 *     });
 *
 * Sub-suites don't need name properties, and may also omit the 'tests' nesting if no lifecycle functions are in use.
 * The rule is that if a 'tests' property isn't in the sub-suite object, then every property is assumed to refer to a
 * test.
 *
 *     registerSuite('foo', {
 *         fooStuff {
 *             bar() {},
 *             baz() {}
 *         }
 *     });
 */
var __assign = (this && this.__assign) || Object.assign || function(t) {
    for (var s, i = 1, n = arguments.length; i < n; i++) {
        s = arguments[i];
        for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
            t[p] = s[p];
    }
    return t;
};
(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", "../Suite", "../Test", "../../intern"], factory);
    }
})(function (require, exports) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    var Suite_1 = require("../Suite");
    var Test_1 = require("../Test");
    var intern_1 = require("../../intern");
    /**
     * Importable interface that uses the currently installed global executor
     */
    function registerSuite(name, descriptorOrFactory) {
        return _registerSuite(intern_1.default(), name, descriptorOrFactory);
    }
    exports.default = registerSuite;
    /**
     * Interface factory used by Executor
     */
    function getInterface(executor) {
        return {
            registerSuite: function (name, descriptorOrFactory) {
                return _registerSuite(executor, name, descriptorOrFactory);
            }
        };
    }
    exports.getInterface = getInterface;
    function isSuiteDescriptorFactory(value) {
        return typeof value === 'function';
    }
    exports.isSuiteDescriptorFactory = isSuiteDescriptorFactory;
    function createSuite(name, parent, descriptor, SuiteClass, TestClass) {
        var options = { name: name, parent: parent };
        var tests;
        // Initialize a new SuiteOptions object from the provided ObjectSuiteDescriptor
        if (isObjectSuiteDescriptor(descriptor)) {
            Object.keys(descriptor).filter(function (key) {
                return key !== 'tests';
            }).forEach(function (key) {
                var optionsKey = key;
                // Convert 'setup' and 'teardown' to 'before' and 'after'
                if (key === 'setup') {
                    parent.executor.emit('deprecated', {
                        original: 'Suite#setup',
                        replacement: 'Suite#before'
                    });
                    optionsKey = 'before';
                }
                else if (key === 'teardown') {
                    parent.executor.emit('deprecated', {
                        original: 'Suite#teardown',
                        replacement: 'Suite#after'
                    });
                    optionsKey = 'after';
                }
                options[optionsKey] = descriptor[key];
            });
            tests = descriptor.tests;
        }
        else {
            tests = descriptor;
        }
        var suite = new SuiteClass(options);
        Object.keys(tests).map(function (name) {
            var thing = tests[name];
            if (Test_1.isTestFunction(thing)) {
                return new TestClass({ name: name, test: thing, parent: suite });
            }
            return createSuite(name, suite, __assign({}, thing), SuiteClass, TestClass);
        }).forEach(function (suiteOrTest) {
            suite.add(suiteOrTest);
        });
        return suite;
    }
    exports.createSuite = createSuite;
    function isObjectSuiteDescriptor(value) {
        return typeof value === 'object' && typeof value.tests === 'object';
    }
    function _registerSuite(executor, name, descriptorOrFactory) {
        executor.addSuite(function (parent) {
            // Enable per-suite closure, to match feature parity with other interfaces like tdd/bdd more closely;
            // without this, it becomes impossible to use the object interface for functional tests since there is no
            // other way to create a closure for each main suite
            var descriptor;
            if (isSuiteDescriptorFactory(descriptorOrFactory)) {
                descriptor = descriptorOrFactory();
            }
            else {
                descriptor = descriptorOrFactory;
            }
            parent.add(createSuite(name, parent, descriptor, Suite_1.default, Test_1.default));
        });
    }
});
//# sourceMappingURL=object.js.map