/** * Functions & classes, which content is trivial or|and doesn't require * complex implementation (<10 SLOC mostly). * * @module */ const os = require("os"); const util = require("util"); const _ = require("lodash"); const BaseError = require("es6-error"); /** * Creates a new instance of `glacejs` error. * * @memberOf module:glace-utils * @class * @classdesc A base class for exceptions and errors, which are raised by * `glacejs` framework or its plugins. Any `glacejs` exception should be * inherited from this class for good style. * @arg {string} message - Error message. */ const GlaceError = function (message) { BaseError.call(this, message); }; util.inherits(GlaceError, BaseError); /** * @memberOf module:glace-utils * @property {string} hostname - Host name of machine where `glacejs` framework is * launched. Despite of machine hostname can be changed during script execution * the probability that hostname will be changed during tests execution is low. * That's why it's kept as property and in low case, because hostname is case * insensitive. */ const hostname = os.hostname().toLowerCase(); /** * Pick default value for variable among listed values. * * @memberOf module:glace-utils * @function * @arg {...*} values - Sequence of variable values. * @return {*} First defined value or `null` if no one is defined. * * @example * U.coalesce(); // null * U.coalesce(undefined); // null * U.coalesce(undefined, 1); // 1 * U.coalesce(undefined, 1, 2); // 1 * U.coalesce(null, 1); // null */ const coalesce = function () { for (const arg of arguments) if (typeof arg !== "undefined") return arg; return null; }; /** * Capitalizes the first letter of a string. It doesn't influence to case * of other letters. * * @memberOf module:glace-utils * @function * @arg {string} string - String to capitalize. * @return {string} Capitalized string. * * @example * U.capitalize('hello'); // 'Hello' * U.capitalize('Hello'); // 'Hello' * U.capitalize('hEllo'); // 'HEllo' */ const capitalize = string => { return string.charAt(0).toUpperCase() + string.slice(1); }; /** * Creates each to each combinations of sets. * * @memberOf module:glace-utils * @function * @arg {Array<Array>} l - Array of arrays to combine. * @arg {?function} [p] - Function to process element before adding to combination. * It passes two arguments: * `e` - a new element to add; * `c` - assembling combination; * By default it just pushes `e` to `c`. * @return {Array<Array>} List of combinations. * * @example * each2each([[1, 2], [3, 4]]); // [[1, 3], [1, 4], [2, 3], [2, 4]] * each2each([[1, 2], [3, 4]], e => e + 1); // [[2, 4], [2, 5], [3, 4], [3, 5]] * each2each([[1, 2], [3, 4]], (e, c) => e + _.sum(c)); // [[1, 4], [1, 5], [2, 5], [2, 6]] */ const each2each = (l, p = e => e) => { let r = [[]]; for (const i of l) { const t = []; for (const j of r) { for (const e of i) { const c = _.clone(j); c.push(p(e, c)); t.push(c); } } r = t; } return r; }; /** * Splits string to array by delimiter. * * @memberOf module:glace-utils * @function * @arg {string} s - String to split. * @arg {char} d - String delimiter. * @return {array<string>} * * @example * U.splitBy("a, b, c", ","); // ['a', 'b', 'c'] */ const splitBy = (s, d) => _.filter(_.map(s.split(d), e => e.trim())); /** * Checks if text contains words or no. * * @memberOf module:glace-utils * @function * @arg {string} string - Original text. * @arg {string} words - Checking words. * @return {boolean} - `true` if text contains words, `false` otherwise. * * @example * U.textContains("hello world", "hello world"); // true */ const textContains = (text, words) => { if (!text) return false; if (!words) return true; text = text.toLowerCase(); words = words.toLowerCase().split(/ +/g); return _.isEmpty(missedWords(text, words, true)); }; /** * Detects words if they are missed in text (case-sensitive). * * @memberOf module:glace-utils * @function * @arg {string} text - Text where words are looked for. * @arg {string[]} words - Filtered words. * @arg {boolean} [firstMissedOnly=false] - Flag to return first missed word only. * It reduces searching time and recommended to use if not need to get all missed words. * @returns {string[]} - Array of missed words. * * @example * U.missedWords("hello world", ["hello", "man"]); // ["man"] */ const missedWords = (text, words, firstMissedOnly = false) => { if (!text || _.isEmpty(words)) { if (firstMissedOnly && !_.isEmpty(words)) { return words.slice(0, 1); } else { return words; } } const missed = []; for (const word of words) { if (text.includes(word)) continue; if (firstMissedOnly) return [word]; missed.push(word); } return missed; }; module.exports = { GlaceError, hostname, coalesce, capitalize, each2each, splitBy, textContains, missedWords, };