@secjs/utils
Version:
Utils functions and classes for Node.js
306 lines (258 loc) • 6.92 kB
JavaScript
/**
* @secjs/utils
*
* (c) João Lenon <lenonSec7@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
import ms from 'ms'
import bytes from 'bytes'
import { getReasonPhrase, getStatusCode } from 'http-status-codes'
import { Is } from '#src/Helpers/Is'
import { String } from '#src/Helpers/String'
import { Options } from '#src/Helpers/Options'
import { InvalidNumberException } from '#src/Exceptions/InvalidNumberException'
export class Parser {
/**
* Parse a string to array.
*
* @param {string} string
* @param {string} separator
* @return {string[]}
*/
static stringToArray(string, separator) {
return string.split(separator).map(index => index.trim())
}
/**
* Parse an array of strings to a string.
*
* @param {string[]} values
* @param {{
* separator?: string,
* pairSeparator?: string,
* lastSeparator?: string
* }} [options]
* @return {string}
*/
static arrayToString(values, options) {
if (values.length === 0) {
return ''
}
if (values.length === 1) {
return values[0]
}
if (values.length === 2) {
return `${values[0]}${options?.pairSeparator || ' and '}${values[1]}`
}
const normalized = Options.create(options, {
separator: ', ',
lastSeparator: ' and ',
})
return (
values.slice(0, -1).join(normalized.separator) +
normalized.lastSeparator +
values[values.length - 1]
)
}
/**
* Parse a string to number or Coordinate.
*
* @param {string} string
* @param {boolean} isCoordinate
* @throws {InvalidNumberException}
* @return {number}
*/
static stringToNumber(string, isCoordinate = false) {
if (!string.replace(/\D/g, '')) {
throw new InvalidNumberException(string)
}
string = string.replace(/\D/g, '')
if (string.length >= 9 || isCoordinate) {
return parseFloat(string)
}
return parseInt(string)
}
/**
* Parse an object to form data.
*
* @param {any} object
* @return {string}
*/
static jsonToFormData(object) {
return Object.keys(object)
.reduce((previous, current) => {
return previous + `&${current}=${encodeURIComponent(object[current])}`
}, '')
.substring(1)
}
/**
* Parse form data to json.
*
* @param {string} formData
* @return {any}
*/
static formDataToJson(formData) {
const object = {}
if (formData.startsWith('?')) formData = formData.replace('?', '')
formData.split('&').forEach(queries => {
const query = queries.split('=')
object[decodeURIComponent(query[0])] = decodeURIComponent(query[1])
})
return object
}
/**
* Parses all links inside the string to HTML link
* with <a href= .../>.
*
* @param {string} string
* @return {string}
*/
static linkToHref(string) {
const regex = /(https?:\/\/[^\s]+)/g
return string.replace(regex, '<a href="$1">$1</a>')
}
/**
* Parses a number to Byte format.
*
* @param {number} value
* @param {object} [options]
* @param {number} [options.decimalPlaces=2]
* @param {number} [options.fixedDecimals=false]
* @param {string} [options.thousandsSeparator=]
* @param {string} [options.unit=]
* @param {string} [options.unitSeparator=]
* @return {string}
*/
static sizeToByte(value, options) {
return bytes.format(value, options)
}
/**
* Parses a byte format to number.
*
* @param {string|number} byte
* @return {number}
*/
static byteToSize(byte) {
return bytes.parse(byte)
}
/**
* Parses a string to MS format.
*
* @param {string} value
* @return {number}
*/
static timeToMs(value) {
return ms(value)
}
/**
* Parses an MS number to time format.
*
* @param {number} value
* @param {boolean} long
* @return {string}
*/
static msToTime(value, long = false) {
return ms(value, { long })
}
/**
* Parses the status code number to it reason in string.
*
* @param {string|number} status
* @return {string}
*/
static statusCodeToReason(status) {
return String.toConstantCase(getReasonPhrase(status))
}
/**
* Parses the reason in string to it status code number
*
* @param {string} reason
* @return {number}
*/
static reasonToStatusCode(reason) {
reason = String.toSentenceCase(reason, true)
if (reason === 'Ok') reason = 'OK'
return getStatusCode(reason)
}
/**
* Parses the database connection url to connection object.
*
* @param {string} url
* @return {{
* protocol: string,
* user?: string,
* password?: string,
* host: string|string[],
* port?: number,
* database: string,
* options?: any,
* }}
*/
static dbUrlToConnectionObj(url) {
const urlRegexp =
/^([^:\\/\s]+):\/\/((.*):(.*)@|)(.*)(:(.*)|)\/(.*)(\?(.+))?/
/** @type {any[]} */
const matcher = url.match(urlRegexp)
const connectionObject = {
protocol: matcher[1],
user: null,
password: null,
host: null,
port: null,
database: matcher[8],
options: {},
}
if (matcher[5].includes(',')) {
connectionObject.host = matcher[5].split(',')
} else {
connectionObject.host = matcher[5]
if (matcher[5].includes(':')) {
const [h, p] = matcher[5].split(':')
connectionObject.host = h
connectionObject.port = parseInt(p)
}
}
if (connectionObject.database.includes('?')) {
const [database, options] = connectionObject.database.split('?')
connectionObject.database = database
connectionObject.options = this.formDataToJson(options)
}
if (matcher[3]) connectionObject.user = matcher[3]
if (matcher[4]) connectionObject.password = matcher[4]
return connectionObject
}
/**
* Parses the database connection object to connection url.
*
* @param {{
* protocol: string,
* user?: string,
* password?: string,
* host: string|string[],
* port?: number,
* database: string,
* options?: any,
* }} object
* @return {string}
*/
static connectionObjToDbUrl(object) {
const { protocol, user, password, host, port, database, options } = object
let url = `${protocol}://`
if (user && password) {
url = url.concat(user).concat(`:${password}`).concat('@')
}
if (Is.Array(host)) {
url = url.concat(host.join(','))
} else {
url = url.concat(host)
/**
* If port exists and host does not include more than one host
*/
if (port && !host.includes(',')) url = url.concat(`:${port}`)
}
url = url.concat(`/${database}`)
if (!Is.Empty(options)) url = url.concat(`?${this.jsonToFormData(options)}`)
return url
}
}