ems-node-app-utils
Version:
Basic JS utilities for use in NodeJS applications developed by Educational Media Solutions
213 lines (200 loc) • 6.82 kB
JavaScript
const _ = require("underscore");
const https = require("https");
exports.alphabetize = function(...parameters) {
if (typeof parameters[0] === 'string') {
// if this method is supplied as a callback to Array.sort
const a = parameters[0];
const b = parameters[1];
if (a > b)
return 1;
if (a < b)
return -1;
return 0;
}
else {
// if we're sorting a list with a supplied key to alphabetize
const list = parameters[0];
const property = parameters[1];
list.sort((a, b) => {
if (a[property] > b[property])
return 1;
if (a[property] < b[property])
return -1;
return 0;
});
return list;
}
}
exports.clone = function(obj) {
if (obj === null || obj === undefined)
return obj;
return JSON.parse(JSON.stringify(obj));
}
exports.dateStrings = function(date) {
date = date || new Date();
return {
year: date.getFullYear(),
month: (date.getMonth() + 1).toString().padStart(2, '0'),
date: date.getDate().toString().padStart(2, '0'),
time: `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`,
seconds: date.getSeconds().toString().padStart(2, '0'),
};
}
exports.delay = function(method, ms = 0) {
return setTimeout(method, ms);
}
exports.empty = function(e) {
return exports.falsy(e);
}
exports.enumKeys = function(obj) {
return Object.keys(obj).filter(k => Number.isNaN(+k));
}
exports.enumValues = function(obj) {
const output = [];
for (const value of enumKeys(obj)) {
output.push(obj[value]);
}
return output;
}
exports.falsy = function(e) {
if (typeof e === 'string' && exports.trim(e).match(/^false$/i))
return true;
if (typeof e === 'string')
return _.isEmpty(e.replace(/\s+/gim, ''));
if (typeof e === 'boolean')
return e === false;
if (!isNaN(parseInt(e, 10)))
return e === 0;
return _.isEmpty(e);
}
exports.focus = function(selector) {
const element = document.querySelector(selector);
if (!element || !element.focus)
return 0;
return delay(() => element.focus());
}
exports.getLargestRemainder = function(values, desiredSum) {
let sum = 0;
let valueParts = values.map((value, index) => {
const integerValue = value || 0;
sum += integerValue;
return {
integer: integerValue,
decimal: value % 1,
originalIndex: index,
};
});
if (sum !== desiredSum && sum) {
valueParts = valueParts.sort((a, b) => b.decimal - a.decimal);
const diff = desiredSum - sum;
let i = 0;
while (i < diff) {
valueParts[i].integer++;
i++;
}
}
return valueParts.sort((a, b) => a.originalIndex - b.originalIndex).map((p) => p.integer);
}
exports.isset = function(e) {
return exports.truthy(e);
}
exports.kebab = function(e) {
if (_.isEmpty(e))
return e;
return e.toLowerCase().replace(/\s+/gim, '-').replace(/_/g, '-').replace(/-+/g, '-');
}
exports.replaceItem = function(array, item, key = 'id', position = 'current') {
const lookup = {};
lookup[key] = item[key];
const oldItem = _.findWhere(array, lookup);
if (!oldItem) {
array.unshift(item);
return item;
}
const index = array.indexOf(oldItem);
if (position === 'first') {
array.splice(index, 1);
array.unshift(item);
}
else {
array.splice(index, 1, item);
}
return item;
}
exports.sleep = function(duration = 0) {
return new Promise((resolve) => {
exports.delay(() => resolve(duration), duration);
});
}
exports.snakecase = function(e) {
if (_.isEmpty(e))
return e;
return e.toLowerCase().replace(/\s+/gim, '_').replace(/-/g, '_').replace(/_+/g, '_');
}
exports.tick = function(returnValue) {
return new Promise((resolve, reject) => {
exports.delay(() => resolve(returnValue));
});
}
exports.timestamp = function(date, includeTime = true) {
const info = dateStrings(date);
const time = `${info.time}:${info.seconds}`;
return `${info.year}-${info.month}-${info.date}${includeTime ? time : ''}`;
}
exports.trace = function(...parameters) {
for (let i = 0, count = parameters.length; i < count; i++) {
console.log(parameters[i]);
}
}
exports.trim = function(e) {
if (_.isEmpty(e)) return e;
return e.replace(/^\s+/, '').replace(/\s+$/, '').replace(/\s+/gim," ");
}
exports.truthy = function(e) {
return !exports.falsy(e);
}
exports.validateEmail = function(email) {
if (!email)
return null;
return String(email)
.toLowerCase()
.match(/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/);
}
exports.request = function(hostname, path, method, body, headers) {
return new Promise((resolve, reject) => {
const options = { hostname, path, method, headers, port: 443};
let data = "";
const request = https.request(options, (response) => {
response.on('data', d => { data += d.toString() });
});
request.on('close', (e) => resolve(JSON.parse(data)));
if(typeof body === "object") {
body = JSON.stringify(body);
}
if(body) request.write(body);
request.end();
})
}
exports.password = function(length) {
const upperCaseChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
const lowerCaseChars = 'abcdefghijklmnopqrstuvwxyz';
const numbers = '0123456789';
const specialChars = '!@#$%^&*()-_=+[]{}|;:,.<>?';
length = length ?? 8;
// Ensure each type of character appears at least once
const password = [
upperCaseChars[Math.floor(Math.random() * upperCaseChars.length)], // One uppercase
lowerCaseChars[Math.floor(Math.random() * lowerCaseChars.length)], // One lowercase
numbers[Math.floor(Math.random() * numbers.length)], // One number
specialChars[Math.floor(Math.random() * specialChars.length)], // One special char
];
// Pool of all allowed characters for remaining password characters
const allChars = upperCaseChars + lowerCaseChars + numbers + specialChars;
// Fill the rest of the password length (64 characters) with random characters
for (let i = password.length; i < length; i++) {
password.push(allChars[Math.floor(Math.random() * allChars.length)]);
}
// Shuffle the password array to ensure randomness, then join it into a string
const randomPassword = password.sort(() => Math.random() - 0.5).join('');
return randomPassword;
}