All files / src/utils encodeUrl.js

8.19% Statements 5/61
0% Branches 0/32
0% Functions 0/10
8.19% Lines 5/61

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 1057x 7x     7x                                                                                                                                                           7x       7x                                    
const encodeReserveRE = /[!'()*]/g;
const encodeReserveReplacer = function (e) {
    return '%' + e.charCodeAt(0).toString(16);
};
const commaRE = /%2C/g;
 
function parsePath(path) {
    let hash = '';
    let query = '';
 
    const hashIndex = path.indexOf('#');
    if (hashIndex >= 0) {
        hash = path.slice(hashIndex);
        path = path.slice(0, hashIndex);
    }
 
    const queryIndex = path.indexOf('?');
    if (queryIndex >= 0) {
        query = path.slice(queryIndex + 1);
        path = path.slice(0, queryIndex);
    }
 
    return {
        path,
        query,
        hash,
    };
}
 
function parseQuery(query) {
    const res = {};
    query = query.trim().replace(/^(\?|#|&)/, '');
    if (!query) {
        return res;
    }
    query.split('&').forEach((param) => {
        const parts = param.replace(/\+/g, ' ').split('=');
        const key = decodeURIComponent(parts.shift());
        const val = parts.length > 0 ? decodeURIComponent(parts.join('=')) : null;
 
        if (res[key] === undefined) {
            res[key] = val;
        } else if (Array.isArray(res[key])) {
            res[key].push(val);
        } else {
            res[key] = [res[key], val];
        }
    });
    return res;
}
 
function stringifyQuery(obj) {
    let res;
    if (obj) {
        res = Object.keys(obj).map((key) => {
            const val = obj[key];
            if (val === undefined) {
                return '';
            }
            if (val === null) {
                return encode(key);
            }
            if (Array.isArray(val)) {
                const result = [];
                val.forEach((val2) => {
                    if (val2 === undefined) {
                        return;
                    }
                    if (val2 === null) {
                        result.push(encode(key));
                    } else {
                        result.push(encode(key) + '=' + encode(val2));
                    }
                });
                return result.join('&');
            }
            return encode(key) + '=' + encode(val);
        }).filter((x) => x.length > 0).join('&');
    }
    return res ? ('?' + res) : '';
}
 
const encode = function (str) {
    return encodeURIComponent(str).replace(encodeReserveRE, encodeReserveReplacer).replace(commaRE, ',');
};
 
const encodeUrl = function (url) {
    if (!url) {
        return url;
    }
    try {
        // 包含单个 '%' 的 query 参数会被 decodeURIComponent 解析报错,例如:ABC%DEF
        const parsedPath = parsePath(url || '');
        const path = parsedPath.path;
        const hash = parsedPath.hash;
        const query = parseQuery(parsedPath.query || '');
        return path + stringifyQuery(query) + hash;
    } catch (e) {
        console.log(e);
        return url;
    }
};
 
export default encodeUrl;