<commit_before>'use strict'

import q from 'q'
import fs from 'fs'
import path from 'path'
import merge from 'deepmerge'
import events from 'events'

import RequestHandler from './utils/RequestHandler'
import { RuntimeError } from './utils/ErrorHandler'
import Logger from './utils/Logger'

import safeExecute from './helpers/safeExecute'
import sanitize from './helpers/sanitize'
import mobileDetector from './helpers/mobileDetector'
import detectSeleniumBackend from './helpers/detectSeleniumBackend'
import internalErrorHandler from './helpers/errorHandler'

const INTERNAL_EVENTS = ['init', 'command', 'error', 'result', 'end']
const PROMISE_FUNCTIONS = ['then', 'catch', 'finally']

let EventEmitter = events.EventEmitter

/**
 * WebdriverIO v4
 */
let WebdriverIO = function (args, modifier) {
    let prototype = Object.create(Object.prototype)
    let eventHandler = new EventEmitter()
    let fulFilledPromise = q()
    let stacktrace = []
    let commandList = []

    const EVENTHANDLER_FUNCTIONS = Object.getPrototypeOf(eventHandler)

    /**
     * merge default options with given user options
     */
    let options = merge({
        protocol: 'http',
        waitforTimeout: 500,
        coloredLogs: true,
        logLevel: 'silent',
        baseUrl: null,
        onError: []
    }, typeof args !== 'string' ? args : {})

    /**
     * define Selenium backend given on user options
     */
    options = merge(detectSeleniumBackend(args), options)

    /**
     * only set globals we wouldn't get otherwise
     */
    if (!process.env.WEBDRIVERIO_COLORED_LOGS) {
        process.env.WEBDRIVERIO_COLORED_LOGS = options.coloredLogs
    }

    let logger = new Logger(options, eventHandler)
    let requestHandler = new RequestHandler(options, eventHandler, logger)

    /**
     * assign instance to existing session
     */
    if (typeof args === 'string') {
        requestHandler.sessionID = args
    }

    /**
     * sanitize error handler
     */
    if (!Array.isArray(options.onError)) {
        options.onError = [options.onError]
    }
    options.onError = options.onError.filter((fn) => {
        return typeof fn === 'function'
    })

    let desiredCapabilities = merge({
        browserName: 'firefox',
        version: '',
        javascriptEnabled: true,
        locationContextEnabled: true,
        handlesAlerts: true,
        rotatable: true,
        platform: 'ANY'
    }, options.desiredCapabilities || {})

    let { isMobile, isIOS, isAndroid } = mobileDetector(desiredCapabilities)

    let resolve = function (result, onFulfilled, onRejected, context) {
        if (typeof result === 'function') {
            this.isExecuted = true
            result = result.call(this)
        }

        /**
         * run error handler if command fails
         */
        if (result instanceof Error) {
            let _result = result
            this.defer.reject(result)

            return Promise.all(internalErrorHandler.map((fn) => {
                return fn.call(context, result)
            })).then((res) => {
                const handlerResponses = res.filter((r) => !!r)

                /**
                 * if no handler was triggered trough actual error
                 */
                if (handlerResponses.length === 0) {
                    return callErrorHandlerAndReject.call(context, _result, onRejected)
                }

                return onFulfilled.call(context, handlerResponses[0])
            }, (e) => {
                return callErrorHandlerAndReject.call(context, e, onRejected)
            })
        }

        this.defer.resolve(result)
        return this.promise
    }

    /**
     * middleware to call on error handler in wdio mode
     */
    let callErrorHandlerAndReject = function (err, onRejected) {
        /**
         * only call error handler if there is any and if error has bubbled up
         */
        if (this.depth !== 0 || options.onError.length === 0) {
            return reject.call(this, err, onRejected)
        }

        return new Promise((r) => {
            return Promise.all(options.onError.map((fn) => {
                if (!global.wdioSync) {
                    return fn.call(this, err)
                }

                return new Promise((r) => global.wdioSync(fn, r).call(this, err))
            })).then(r, r)
        }).then(() => {
            return reject.call(this, err, onRejected)
        })
    }

    /**<commit_msg>throw if an error handler fails<commit_after>'use strict'

import q from 'q'
import fs from 'fs'
import path from 'path'
import merge from 'deepmerge'
import events from 'events'

import RequestHandler from './utils/RequestHandler'
import { RuntimeError } from './utils/ErrorHandler'
import Logger from './utils/Logger'

import safeExecute from './helpers/safeExecute'
import sanitize from './helpers/sanitize'
import mobileDetector from './helpers/mobileDetector'
import detectSeleniumBackend from './helpers/detectSeleniumBackend'
import internalErrorHandler from './helpers/errorHandler'

const INTERNAL_EVENTS = ['init', 'command', 'error', 'result', 'end']
const PROMISE_FUNCTIONS = ['then', 'catch', 'finally']

let EventEmitter = events.EventEmitter

/**
 * WebdriverIO v4
 */
let WebdriverIO = function (args, modifier) {
    let prototype = Object.create(Object.prototype)
    let eventHandler = new EventEmitter()
    let fulFilledPromise = q()
    let stacktrace = []
    let commandList = []

    const EVENTHANDLER_FUNCTIONS = Object.getPrototypeOf(eventHandler)

    /**
     * merge default options with given user options
     */
    let options = merge({
        protocol: 'http',
        waitforTimeout: 500,
        coloredLogs: true,
        logLevel: 'silent',
        baseUrl: null,
        onError: []
    }, typeof args !== 'string' ? args : {})

    /**
     * define Selenium backend given on user options
     */
    options = merge(detectSeleniumBackend(args), options)

    /**
     * only set globals we wouldn't get otherwise
     */
    if (!process.env.WEBDRIVERIO_COLORED_LOGS) {
        process.env.WEBDRIVERIO_COLORED_LOGS = options.coloredLogs
    }

    let logger = new Logger(options, eventHandler)
    let requestHandler = new RequestHandler(options, eventHandler, logger)

    /**
     * assign instance to existing session
     */
    if (typeof args === 'string') {
        requestHandler.sessionID = args
    }

    /**
     * sanitize error handler
     */
    if (!Array.isArray(options.onError)) {
        options.onError = [options.onError]
    }
    options.onError = options.onError.filter((fn) => {
        return typeof fn === 'function'
    })

    let desiredCapabilities = merge({
        browserName: 'firefox',
        version: '',
        javascriptEnabled: true,
        locationContextEnabled: true,
        handlesAlerts: true,
        rotatable: true,
        platform: 'ANY'
    }, options.desiredCapabilities || {})

    let { isMobile, isIOS, isAndroid } = mobileDetector(desiredCapabilities)

    let resolve = function (result, onFulfilled, onRejected, context) {
        if (typeof result === 'function') {
            this.isExecuted = true
            result = result.call(this)
        }

        /**
         * run error handler if command fails
         */
        if (result instanceof Error) {
            let _result = result
            this.defer.reject(result)

            return Promise.all(internalErrorHandler.map((fn) => {
                return fn.call(context, result)
            })).then((res) => {
                const handlerResponses = res.filter((r) => !!r)

                /**
                 * if no handler was triggered trough actual error
                 */
                if (handlerResponses.length === 0) {
                    return callErrorHandlerAndReject.call(context, _result, onRejected)
                }

                return onFulfilled.call(context, handlerResponses[0])
            }, (e) => {
                return callErrorHandlerAndReject.call(context, e, onRejected)
            })
        }

        this.defer.resolve(result)
        return this.promise
    }

    /**
     * middleware to call on error handler in wdio mode
     */
    let callErrorHandlerAndReject = function (err, onRejected) {
        /**
         * only call error handler if there is any and if error has bubbled up
         */
        if (this.depth !== 0 || options.onError.length === 0) {
            return reject.call(this, err, onRejected)
        }

        return new Promise((resolve, reject) => {
            return Promise.all(options.onError.map((fn) => {
                if (!global.wdioSync) {
                    return fn.call(this, err)
                }

                return new Promise((r) => global.wdioSync(fn, r).call(this, err))
            })).then(resolve, reject)
        }).then(() => {
            return reject.call(this, err, onRejected)
        })
    }

    /**
{'fraction_non_alphanumeric': 0.11319700525198347, 'fraction_numerical': 0.0017879092636048722, 'mean_word_length': 2.1726338177951083, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4581493', 'n_tokens_mistral': 2524, 'n_tokens_neox': 2453, 'n_words': 648}