UNPKG

mcode-list

Version:

Our List Processing functions. These support list of Objects--ints, string, JSON, any--that are ordered and related to other lists on the same topic. These can be used to swap one item in a list with its corresponding element in a realted list. This is si

350 lines (320 loc) 14.7 kB
// #region F I L E // <copyright file="mcode-list/index.js" company="MicroCODE Incorporated">Copyright © 2022-2024 MicroCODE, Inc. Troy, MI</copyright><author>Timothy J. McGuire</author> // #region M O D U L E // #region D O C U M E N T A T I O N /** * Project: MicroCODE MERN Applications * Customer: Internal + MIT xPRO Course * @module 'mcode-list.js' * @memberof mcode * @created January 2022-2024 * @author Timothy McGuire, MicroCODE, Inc. * @description > * MicroCODE Shared List Processing Library * * LICENSE: * -------- * MIT License: MicroCODE.mcode-list * * Copyright (c) 2022-2024 Timothy McGuire, MicroCODE, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * DESCRIPTION: * ------------ * This module implements the MicroCODE's Common JavaScript functions for list processing. * * * REFERENCES: * ----------- * 1. MIT xPRO Course: Professional Certificate in Coding: Full Stack Development with MERN * * 2. LADDERS® source code: MACRO-11, MACRO-32, C#, and JavaScript. * * * * * MODIFICATIONS: * -------------- * Date: By-Group: Rev: Description: * * 30-Jan-2024 TJM-MCODE {0001} New module for common reusable JavaScript list processing functions. * 01-Feb-2024 TJM-MCODE {0002} Changed to the Universal Module Definition (UMD) pattern to support AMD, * CommonJS/Node.js, and browser global in our exported module. * 01-Feb-2024 TJM-MCODE {0003} Swap() and Call() now throw an error if the 'keys' and 'values' lists are not the same length, * instead of logging the error and returning a default value. * 29-Jan-2024 TJM-MCODE {0004} Updated Call() to accept and pass arguments to the functions in the 'functions' list. * 04-Sep-2024 TJM-MCODE {0005} Updated Call() to take an optional comparison function to find the 'key' in the 'keys' list. * 08-Sep-2024 TJM-MCODE {0006} Added swapif() and callif() functions to support custom key matching functions. * * * * * NOTE: This module follow's MicroCODE's JavaScript Style Guide and Template JS file, see: * * o https://github.com/MicroCODEIncorporated/JavaScriptSG * o https://github.com/MicroCODEIncorporated/TemplatesJS * */ // #endregion // #region I M P O R T S const _log = require('mcode-log'); // #endregion // #region T Y P E S // #endregion // #region I N T E R F A C E S // #endregion // #region C O N S T A N T S, F U N C T I O N S – P U B L I C // MicroCODE: define this module's name for our 'mcode-log' package const MODULE_NAME = 'mcode-list.js'; /** * @func getIndex * @memberof mcode * @desc a private helper function that returns the index of a 'key' in a 'keys' list * or the last/default index in the 'keys' list if not found. * @param {any} key a JavaScript value viewed as a 'key' in the 'keys' list. * @param {any[]} keys a JavaScript array of values viewed as 'keys' list. * @returns {number} the index of the 'key' in the 'keys' list or the last/default index in the list if not found */ function getIndex(key, keys) { let index = keys.indexOf(key); return (index === -1) ? (keys.length - 1) : index; } /** * @namespace mcode * @desc mcode namespace containing functions and constants. */ const mcode = { /** * @func swap * @memberof mcode * @desc Swaps a 'key' from a 'keys' list with a 'value' in a 'values' list. * @api public * @param {any} key a JavaScript value viewed as a 'key' in the 'keys' list. * @param {any[]} keys a JavaScript array of values viewed as a 'keys' list. * @param {any[]} values a JavaScript array of values viewed as the 'values' list. * @returns {any} the value from the 'values' list corresponding to the 'key' in the 'keys' list. * * @example * let list1 = [1, 2, 3, 4, 5, 0]; * let list2 = ['one', 'two', 'three', 'four', 'five', 'default']; * let list3 = [false, true, false, true, false, false]; * let list4 = [{ key: 1, property: ONE }, * { key: 2, property: TWO }, * { key: 3, property: THREE }, * { key: 4, property: FOUR }, * { key: 5, property: FIVE }, * { key: 0, property: DEFAULT }]; * * let key = null; * let value = null; * * 1) straight swap of two values... * * key = 3; * value = mcode.swap(key, list1, list2); // value = 'three' * * key = 6; * value = mcode.swap(key, list1, list2); // value = 'default' * * key = 0; * value = mcode.swap(key, list1, list2); // value = 'default' * * 2) the same lists can be used the other way around... * * key = 'three'; * value = mcode.swap(key, list2, list1); // value = 3 * * key = 'six'; * value = mcode.swap(key, list2, list1); // value = 0 * * 3) any two lists on the same subject (i.e.: the same length) can be used... * * key = 3; * value = mcode.swap(key, list1, list3); // value = false * * key = 'three'; * value = mcode.swap(key, list2, list4); // value = { key: 4, property: FOUR } * * * ...seems simple enough, but keep in mind that the 'key' and 'value' in the lists can be any JavaScript value, including: * * - a number * - a string * - a boolean * - a function * - a class * - a module * - a BigInt * - a Promise * - an Object * - an Array * - a JSON object * - null * - undefined * etc. * */ swap: function (key, keys, values) { // ensure the 'keys' and 'values' lists are the same length if (keys.length !== values.length) { throw new Error(`mcode-list.swap(): The 'keys' and 'values' lists are not the same length, keys.length:${keys.length} !== values.length:${values.length}`); } // return the value from the 'values' list corresponding to the 'key' in the 'keys' list, or default value return values[getIndex(key, keys)]; }, /** * @func swapif * @memberof mcode * @desc Swaps a 'key' from a 'keys' list with a 'value' in a 'values' list using a custom comparison. * @api public * @param {any} key a JavaScript value viewed as a 'key' in the 'keys' list. * @param {any[]} keys a JavaScript array of values viewed as a 'keys' list. * @param {any[]} values a JavaScript array of values viewed as the 'values' list. * @param {function} compareFn a comparison function to select the 'key' in the 'keys' list. * @returns {any} the value from the 'values' list corresponding to the 'key' in the 'keys' list. */ swapif: function (key, keys, values, compareFn = (a, b) => a === b) { // ensure the 'keys' and 'values' lists are the same length if (keys.length !== values.length) { throw new Error(`mcode-list.swap(): The 'keys' and 'values' lists are not the same length, keys.length:${keys.length} !== values.length:${values.length}`); } // Find the index of the 'key' in the 'keys' array using the comparison function {0006} const index = keys.findIndex(k => compareFn(key, k)); // If 'key' is found, return the corresponding value; otherwise, return the last value as the default if (index !== -1) { return values[index]; } else { return values[values.length - 1]; // return default (last) value } }, /** * @func call * @memberof mcode * @desc Calls a function from a 'functions' list using a 'key' index found in a 'keys' list, passing additional arguments to the function. * @api public * @param {any} key a JavaScript value viewed as a 'key' in the 'keys' list. * @param {any[]} keys a JavaScript array of values viewed as 'keys' list. * @param {function[]} functions a JavaScript array of functions viewed as 'values' list. * @param {...any} args additional arguments to be passed to the selected function. * @returns {any} the return value from the function called in 'functions' list corresponding to the 'key' in the 'keys' list. * * @example * let keys = [1, 2, 3, 4, 5, null]; * let functions = [function1, function2, function3, function4, function5, default]; * let key = 3; * let value = mcode.call(key, keys, functions, 'arg1', 'arg2'); // value = (return value of function3('arg1', 'arg2')) */ call: function (key, keys, functions, ...args) { // ensure the source and destination lists are the same length if (keys.length !== functions.length) { throw new Error(`mcode-list.call(): The 'keys' and 'functions' lists are not the same length, keys.length:${keys.length} !== functions.length:${functions.length}`); } // retrieve the index of the key or the default index const index = getIndex(key, keys); // call the function from the 'functions' list corresponding to the 'key' in the 'keys' list, passing the additional arguments return functions[index](...args); }, /** * @func callif * @memberof mcode * @desc Calls a function from a 'functions' list using a 'key' index found in a 'keys' list, * passing additional arguments to the function, and using a customed comparison function. * @api public * @param {any} key a JavaScript value viewed as a 'key' in the 'keys' list. * @param {any[]} keys a JavaScript array of values viewed as 'keys' list. * @param {function[]} functions a JavaScript array of functions viewed as 'values' list. * @param {function} compareFn a comparison function to find the 'key' in the 'keys' list. * @param {...any} args additional arguments to be passed to the selected function. * @returns {any} the return value from the function called in 'functions' list corresponding to the 'key' in the 'keys' list. */ callif: function (key, keys, functions, compareFn = (a, b) => a === b, ...args) { // ensure the 'keys' and 'functions' lists are the same length if (keys.length !== functions.length) { throw new Error(`mcode-list.call(): The 'keys' and 'functions' lists are not the same length, keys.length:${keys.length} !== functions.length:${functions.length}`); } // Find the index of the 'key' in the 'keys' array using the comparison function {0006} const index = keys.findIndex(k => compareFn(key, k)); // If 'key' is found, call the corresponding function; otherwise, call the last function as the default if (index !== -1) { return functions[index](...args); } else { return functions[functions.length - 1](...args); // Call the default (last) function } } }; // #endregion // #region M E T H O D - E X P O R T S // Immediately Invoked Function Expression (IIFE) invoked on 'this' which // represents the global object(window in a browser, global in Node.js). // This IIFE returns the 'mcode' object to be assigned to the global object. // The Universal Module Definition (UMD) pattern supports Asynchronous Module Definition (AMD), // CommonJS / Node.js, and Browser 'global' usage. ( /** * @function (IIFE) * @description Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, and browser global * @param {any} root the global object (window, self, global, etc.) being updated. * @param {any} factory a function that returns the exports of the module. This function is invoked in * the context of the global object when the module is loaded. The return value of this function is used * as the exported value of the module when it's not being used with AMD or Node.js module systems. * This function is where you define what your module exports. */ function (root, factory) { if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. define([], factory); } else if (typeof module === 'object' && module.exports) { // Node. Does not work with strict CommonJS, but // only CommonJS-like environments that support module.exports, like Node. module.exports = factory(); } else { // Browser globals (root is 'window') root.mcode = factory(); } }( // root: the global object (window, self, global, etc.) (typeof self !== 'undefined') ? self : this, // factory: a function that returns the exports of the module function () {return mcode;}) ); // #endregion // #endregion // #endregion