UNPKG

@intentjs/hyper-express

Version:

A fork of hyper-express to suit IntentJS requirements. High performance Node.js webserver with a simple-to-use API powered by uWebsockets.js under the hood.

198 lines (172 loc) 6.97 kB
'use strict'; /** * Writes values from focus object onto base object. * * @param {Object} obj1 Base Object * @param {Object} obj2 Focus Object */ function wrap_object(original, target) { Object.keys(target).forEach((key) => { if (typeof target[key] == 'object') { if (Array.isArray(target[key])) return (original[key] = target[key]); // lgtm [js/prototype-pollution-utility] if (original[key] === null || typeof original[key] !== 'object') original[key] = {}; wrap_object(original[key], target[key]); } else { original[key] = target[key]; } }); } /** * This method parses route pattern into an array of expected path parameters. * * @param {String} pattern * @returns {Array} [[key {String}, index {Number}], ...] */ function parse_path_parameters(pattern) { let results = []; let counter = 0; if (pattern.indexOf('/:') > -1) { let chunks = pattern.split('/').filter((chunk) => chunk.length > 0); for (let index = 0; index < chunks.length; index++) { let current = chunks[index]; if (current.startsWith(':') && current.length > 2) { results.push([current.substring(1), counter]); counter++; } } } return results; } /** * This method converts ArrayBuffers to a string. * * @param {ArrayBuffer} array_buffer * @param {String} encoding * @returns {String} String */ function array_buffer_to_string(array_buffer, encoding = 'utf8') { return Buffer.from(array_buffer).toString(encoding); } /** * Copies an ArrayBuffer to a Uint8Array. * Note! This method is supposed to be extremely performant as it is used by the Body parser. * @param {ArrayBuffer} array_buffer */ function copy_array_buffer_to_uint8array(array_buffer) { const source = new Uint8Array(array_buffer); return new Uint8Array(source.subarray(0, source.length)); } /** * Returns a promise which is resolved after provided delay in milliseconds. * * @param {Number} delay * @returns {Promise} */ function async_wait(delay) { return new Promise((resolve, reject) => setTimeout((res) => res(), delay, resolve)); } /** * Merges provided relative paths into a singular relative path. * * @param {String} base_path * @param {String} new_path * @returns {String} path */ function merge_relative_paths(base_path, new_path) { // handle both roots merger case if (base_path == '/' && new_path == '/') return '/'; // Inject leading slash to new_path if (!new_path.startsWith('/')) new_path = '/' + new_path; // handle base root merger case if (base_path == '/') return new_path; // handle new path root merger case if (new_path == '/') return base_path; // strip away leading slash from base path if (base_path.endsWith('/')) base_path = base_path.substr(0, base_path.length - 1); // Merge path and add a slash in between if new_path does not have a starting slash return `${base_path}${new_path}`; } /** * Returns all property descriptors of an Object including extended prototypes. * * @param {Object} prototype */ function get_all_property_descriptors(prototype) { // Retrieve initial property descriptors const descriptors = Object.getOwnPropertyDescriptors(prototype); // Determine if we have a parent prototype with a custom name const parent = Object.getPrototypeOf(prototype); if (parent && parent.constructor.name !== 'Object') { // Merge and return property descriptors along with parent prototype return Object.assign(descriptors, get_all_property_descriptors(parent)); } // Return property descriptors return descriptors; } /** * Inherits properties, getters, and setters from one prototype to another with the ability to optionally define middleman methods. * * @param {Object} options * @param {Object|Array<Object>} options.from - The prototype to inherit from * @param {Object} options.to - The prototype to inherit to * @param {function(('FUNCTION'|'GETTER'|'SETTER'), string, function):function=} options.method - The method to inherit. Parameters are: type, name, method. * @param {function(string):string=} options.override - The method name to override the original with. Parameters are: name. * @param {Array<string>} options.ignore - The property names to ignore */ function inherit_prototype({ from, to, method, override, ignore = ['constructor'] }) { // Recursively call self if the from prototype is an Array of prototypes if (Array.isArray(from)) return from.forEach((f) => inherit_prototype({ from: f, to, override, method, ignore })); // Inherit the descriptors from the "from" prototype to the "to" prototype const to_descriptors = get_all_property_descriptors(to); const from_descriptors = get_all_property_descriptors(from); Object.keys(from_descriptors).forEach((name) => { // Ignore the properties specified in the ignore array if (ignore.includes(name)) return; // Destructure the descriptor function properties const { value, get, set } = from_descriptors[name]; // Determine if this descriptor name would be an override // Override the original name with the provided name resolver for overrides if (typeof override == 'function' && to_descriptors[name]?.value) name = override(name) || name; // Determine if the descriptor is a method aka. a function if (typeof value === 'function') { // Inject a middleman method into the "to" prototype const middleman = method('FUNCTION', name, value); if (middleman) { // Define the middleman method on the "to" prototype Object.defineProperty(to, name, { configurable: true, enumerable: true, writable: true, value: middleman, }); } } else { // Initialize a definition object const definition = {}; // Initialize a middleman getter method if (typeof get === 'function') definition.get = method('GETTER', name, get); // Initialize a middleman setter method if (typeof set === 'function') definition.set = method('SETTER', name, set); // Inject the definition into the "to" prototype if (definition.get || definition.set) Object.defineProperty(to, name, definition); } }); } /** * Converts Windows path backslashes to forward slashes. * @param {string} string * @returns {string} */ function to_forward_slashes(string) { return string.split('\\').join('/'); } module.exports = { parse_path_parameters, array_buffer_to_string, wrap_object, async_wait, inherit_prototype, merge_relative_paths, to_forward_slashes, copy_array_buffer_to_uint8array, };