function parseUri(str, opts) {
    opts = opts || {};
    var o = {
        // eslint-disable-next-line max-len
        key: ['source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'anchor'],
        q: {
            name: 'queryKey',
            parser: /(?:^|&)([^&=]*)=?([^&]*)/g
        },
        parser: {
            // eslint-disable-next-line max-len
            strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
            // eslint-disable-next-line max-len
            loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
        }
    };
    var m = o.parser[opts.strictMode ? 'strict' : 'loose'].exec(str);
    var uri = {};
    var i = 14;
    while (i--)
        { uri[o.key[i]] = m[i] || ''; }
    uri[o.q.name] = {};
    uri[o.key[12]].replace(o.q.parser, function (_t0, t1, t2) {
        if (t1)
            { uri[o.q.name][t1] = t2; }
    });
    return uri;
}
function from npm package `parseUri`, converted to TS to avoid leftpad incident
@param {string} str
@param [opts] - options
@param {boolean} [opts.strictMode] - type of parser