2
\$\begingroup\$

The goal of this module is to take in a string (user input, someone copy and pasting a large list of proxies) and parse it into an array of objects.

I appreciate any and all feedback, but I'm specifically interested in improving the stringToProxy function.

Namely I'm unsure about mutating the string parameter, seems like there could be a better solution. And the way I'm declaring the proxy at the beginning of the function feels wrong to me (using As) but I couldn't think of any better solution. I also feel as though I may be overusing string.split().

Thanks for your time!

Edit: Incorporated the url module as Nazar recommended. I'm happy with this solution but still taking feedback.

const { URL } = require("url");

interface Proxy {
    host: string;
    port: number;
    protocol: string;
    auth?: {
        username: string;
        password: string;
    };
}

function parse(string: string): Proxy[] {
    const rawArray = stringToArray(string);
    const fixedArray = rawArray.map((string) => fixProxyString(string));
    const proxyArray = fixedArray.map((string) => stringToProxy(string));
    return proxyArray;
}

function stringToArray(string: string): string[] {
    return string.trim().replace(/[ ,\n]+/g, ",").split(",");
}

function fixProxyString(string: string): string {
    return string.includes("://") ? string : `http://${string}`; //if user doesnt specify a protocol, default to http
}

function stringToProxy(string: string): Proxy {
    const url = new URL(string);
    return {
        host: url.hostname,
        port: url.port ? parseInt(url.port) : 80, //if proxy is 80 url will ignore it so i need to explicitly add it
        protocol: url.protocol.slice(0, -1), //removing the colon
        auth: url.username ? { username: url.username, password: url.password } : undefined
    };
}

export = parse;

Before edit:

interface Proxy {
    host: string;
    port: number;
    auth?: {
        username: string;
        password: string;
    };
    protocol?: string;
}

function parse(string: string): Proxy[] {
    const rawArray = stringToArray(string);
    const proxyArray = rawArray.map((string) => stringToProxy(string));
    return proxyArray;
}

function stringToArray(string: string): string[] {
    return string.trim().replace(/[ ,\n]+/g, ",").split(",");
}

function stringToProxy(string: string) {
    const proxy = {} as Proxy;

    if (string.includes("://")) {
        const [protocol, remainder] = string.split("://");
        proxy.protocol = protocol;
        string = remainder;
    }
    if (string.includes("@")) {
        const [auth, remainder] = string.split("@");
        const [username, password] = auth.split(":");
        proxy.auth = { username, password };
        string = remainder;
    }
    const [host, port] = string.split(":");
    proxy.port = parseInt(port);
    proxy.host = host;

    return proxy;
}

export = parse;

Usage:

const parse = require("parse-proxy");

parse(`1.1.1.1:80, 2.2.2.2:80, 3.3.3.3:80`)

//result
[
  { host: '1.1.1.1', port: 80 },
  { host: '2.2.2.2', port: 80 },
  { host: '3.3.3.3', port: 80 }
]

parse(`https://user:pass@104.236.55.48:8080\nhttps://user:pass@213.105.29.14:3128`)

//result 
[
  {
    protocol: 'https',
    auth: { username: 'user', password: 'pass' },
    host: '104.236.55.48',
    port: 8080
  },
  {
    protocol: 'https',
    auth: { username: 'user', password: 'pass' },
    host: '213.105.29.14',
    port: 3128
  }
]
\$\endgroup\$
2
  • \$\begingroup\$ I would suggest using a built-in WHATWG API. You can get almost the same output by calling require('url').parse function. \$\endgroup\$ – Nazar Jan 17 at 21:55
  • \$\begingroup\$ Ah yes, that does the trick, thanks for the help! \$\endgroup\$ – DevHigley Jan 17 at 23:49
1
\$\begingroup\$

A couple of small comments:

Don't call your parameter the same thing as its type string: string. This makes the code needlessly difficult to read - don't make the reader waste time wondering whether this string a type or the variable. Use input, source or something else that makes sense.

Don't shadow outer variables/arguments in arrow functions, again this harms readability rawArray.map((string) => fixProxyString(string));. Note that the parenthesis are optional for one parameter too. Consider instead:

function parse(input: string): Proxy[] {
    const rawArray = stringToArray(input);
    const fixedArray = rawArray.map(raw => fixProxyString(raw));
    const proxyArray = fixedArray.map(fixed => stringToProxy(fixed));
    return proxyArray;
}

I think (although not tested) that you can further simplify:

function parse(input: string): Proxy[] {
    return stringToArray(input)
        .map(fixProxyString)
        .map(stringToProxy);
}

You don't need to replace and then split here return string.trim().replace(/[ ,\n]+/g, ",").split(",");. You can just split by the regex directly.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.