diff --git a/Framework/Backend/db/mysql.js b/Framework/Backend/db/mysql.js index a8e5319f3..e3d1b8bfd 100644 --- a/Framework/Backend/db/mysql.js +++ b/Framework/Backend/db/mysql.js @@ -14,7 +14,7 @@ const mysql = require('mysql'); const assert = require('assert'); -const {LogManager} = require('../log/LogManager'); +const { LogManager } = require('../log/LogManager'); /** * MySQL pool wrapper @@ -32,11 +32,11 @@ class MySQL { assert(config.host, 'Missing config value: mysql.host'); assert(config.user, 'Missing config value: mysql.user'); assert(config.database, 'Missing config value: mysql.database'); - config.port = (!config.port) ? 3306 : config.port; - config.connectionLimit = (!config.connectionLimit) ? 25 : config.connectionLimit; - config.queueLimit = (!config.queueLimit) ? 50 : config.queueLimit; - config.password = (!config.password) ? '' : config.password; - config.timeout = (!config.timeout) ? 30000 : config.timeout; + config.port = !config.port ? 3306 : config.port; + config.connectionLimit = config.connectionLimit ?? 25; + config.queueLimit = config.queueLimit ?? 50; + config.password = !config.password ? '' : config.password; + config.timeout = config.timeout ?? 30000; this.config = config; this.logger = LogManager.getLogger(`${process.env.npm_config_log_label ?? 'framework'}/mysql`); @@ -45,7 +45,7 @@ class MySQL { /** * Method to test connection of mysql connector once initialized - * @return {Promise} + * @return {Promise} - a promise that resolves if connection is successful */ testConnection() { return new Promise((resolve, reject) => { @@ -113,4 +113,5 @@ class MySQL { return message; } } + module.exports = MySQL; diff --git a/Framework/Backend/errors/grpcErrorToNativeError.js b/Framework/Backend/errors/grpcErrorToNativeError.js index ac954ce81..8495b2396 100644 --- a/Framework/Backend/errors/grpcErrorToNativeError.js +++ b/Framework/Backend/errors/grpcErrorToNativeError.js @@ -11,16 +11,16 @@ * or submit itself to any jurisdiction. */ -const {InvalidInputError} = require('./InvalidInputError.js'); -const {NotFoundError} = require('./NotFoundError.js'); -const {ServiceUnavailableError} = require('./ServiceUnavailableError.js'); -const {TimeoutError} = require('./TimeoutError.js'); -const {UnauthorizedAccessError} = require('./UnauthorizedAccessError.js'); +const { InvalidInputError } = require('./InvalidInputError.js'); +const { NotFoundError } = require('./NotFoundError.js'); +const { ServiceUnavailableError } = require('./ServiceUnavailableError.js'); +const { TimeoutError } = require('./TimeoutError.js'); +const { UnauthorizedAccessError } = require('./UnauthorizedAccessError.js'); /** * @typedef GrpcError * also known as gRPC Status Object - * + * * @property {number} code - code of the gRPC Status object * @property {string} message - message of the gRPC Status object */ diff --git a/Framework/Backend/errors/updateAndSendExpressResponseFromNativeError.js b/Framework/Backend/errors/updateAndSendExpressResponseFromNativeError.js index 2edc585c2..fbbf59f1f 100644 --- a/Framework/Backend/errors/updateAndSendExpressResponseFromNativeError.js +++ b/Framework/Backend/errors/updateAndSendExpressResponseFromNativeError.js @@ -11,11 +11,11 @@ * or submit itself to any jurisdiction. */ -const {InvalidInputError} = require('./InvalidInputError.js'); -const {NotFoundError} = require('./NotFoundError.js'); -const {ServiceUnavailableError} = require('./ServiceUnavailableError.js'); -const {TimeoutError} = require('./TimeoutError.js'); -const {UnauthorizedAccessError} = require('./UnauthorizedAccessError.js'); +const { InvalidInputError } = require('./InvalidInputError.js'); +const { NotFoundError } = require('./NotFoundError.js'); +const { ServiceUnavailableError } = require('./ServiceUnavailableError.js'); +const { TimeoutError } = require('./TimeoutError.js'); +const { UnauthorizedAccessError } = require('./UnauthorizedAccessError.js'); /** * Given an Express response object and an error, use the response object to set a custom status code and send the message @@ -27,7 +27,7 @@ const {UnauthorizedAccessError} = require('./UnauthorizedAccessError.js'); const updateAndSendExpressResponseFromNativeError = (response, error) => { let status = 500; let title = 'Unknown Error'; - const {message, constructor} = error; + const { message, constructor } = error; switch (constructor) { case InvalidInputError: status = 400; @@ -51,7 +51,7 @@ const updateAndSendExpressResponseFromNativeError = (response, error) => { break; } - response.status(status).json({message, status, title}); + response.status(status).json({ message, status, title }); }; exports.updateAndSendExpressResponseFromNativeError = updateAndSendExpressResponseFromNativeError; diff --git a/Framework/Backend/http/openid.js b/Framework/Backend/http/openid.js index 1b3df1441..0aac0947b 100644 --- a/Framework/Backend/http/openid.js +++ b/Framework/Backend/http/openid.js @@ -12,12 +12,12 @@ * or submit itself to any jurisdiction. */ -const {Issuer, generators, custom} = require('openid-client'); +const { Issuer, generators, custom } = require('openid-client'); const assert = require('assert'); -const {LogManager} = require('../log/LogManager'); +const { LogManager } = require('../log/LogManager'); /** - * Authenticates and authorises users via OpenID Connect (new CERN SSO). + * Authenticates and authorizes users via OpenID Connect (new CERN SSO). * @author Adam Wegrzynek */ class OpenId { @@ -30,7 +30,7 @@ class OpenId { assert(config.secret, 'Missing config value: secret'); assert(config.well_known, 'Missing config value: well_known'); assert(config.redirect_uri, 'Missing config value: redirect_uri'); - config.timeout = (!config.timeout) ? 5000 : config.timeout; + config.timeout = config.timeout ?? 5000; this.config = config; this.code_verifier = generators.codeVerifier(); custom.setHttpOptionsDefaults({ @@ -59,7 +59,7 @@ class OpenId { this.logger.info('Client initialised'); resolve(); }).catch((error) => { - this.logger.error('Initialisation failed: ' + error); + this.logger.error(`Initialisation failed: ${error}`); reject(error); }); }); diff --git a/Framework/Backend/http/server.js b/Framework/Backend/http/server.js index a4c78cc5b..c54856a38 100644 --- a/Framework/Backend/http/server.js +++ b/Framework/Backend/http/server.js @@ -22,7 +22,7 @@ const O2TokenService = require('./../services/O2TokenService.js'); const OpenId = require('./openid.js'); const path = require('path'); const url = require('url'); -const {LogManager} = require('../log/LogManager'); +const { LogManager } = require('../log/LogManager'); /** * HTTPS server verifies identity using OpenID Connect and provides REST API. @@ -39,9 +39,9 @@ class HttpServer { constructor(httpConfig, jwtConfig, connectIdConfig = null) { assert(httpConfig, 'Missing config'); assert(httpConfig.port, 'Missing config value: port'); - httpConfig.tls = (!httpConfig.tls) ? false : httpConfig.tls; - httpConfig.hostname = (!httpConfig.hostname) ? 'localhost' : httpConfig.hostname; - this.limit = (!httpConfig.limit) ? '100kb' : httpConfig.limit; + httpConfig.tls = !httpConfig.tls ? false : httpConfig.tls; + httpConfig.hostname = !httpConfig.hostname ? 'localhost' : httpConfig.hostname; + this.limit = !httpConfig.limit ? '100kb' : httpConfig.limit; this.app = express(); @@ -51,8 +51,8 @@ class HttpServer { if (connectIdConfig) { this.openid = new OpenId(connectIdConfig); this.openid.createIssuer().catch(() => process.exit(1)); - this.ipAddressWhitelist = (!connectIdConfig.sa_whitelist) ? '127.0.0.1' : connectIdConfig.sa_whitelist; - this.serviceAccountRole = (!connectIdConfig.sa_role) ? 'service-account' : connectIdConfig.sa_role; + this.ipAddressWhitelist = !connectIdConfig.sa_whitelist ? '127.0.0.1' : connectIdConfig.sa_whitelist; + this.serviceAccountRole = !connectIdConfig.sa_role ? 'service-account' : connectIdConfig.sa_role; } this.specifyRoutes(); @@ -61,7 +61,7 @@ class HttpServer { assert(httpConfig.cert, 'Missing HTTP config value: cert'); const credentials = { key: fs.readFileSync(httpConfig.key), - cert: fs.readFileSync(httpConfig.cert) + cert: fs.readFileSync(httpConfig.cert), }; this.server = https.createServer(credentials, this.app); this.enableHttpRedirect(); @@ -72,7 +72,8 @@ class HttpServer { } const autoListenFlag = 'autoListen'; - if (!httpConfig.hasOwnProperty(autoListenFlag) || httpConfig[autoListenFlag]) { + + if (!Object.prototype.hasOwnProperty.call(httpConfig, autoListenFlag) || httpConfig[autoListenFlag]) { this.listen(); } @@ -81,7 +82,7 @@ class HttpServer { /** * Starts the server listening for connections. - * @return {Promise} + * @return {Promise} - resolves when server is listening */ listen() { return new Promise((resolve, reject) => { @@ -112,7 +113,7 @@ class HttpServer { * Stops the server from accepting new connections and keeps existing connections. * This function is asynchronous, the server is finally closed when all connections * are ended and the server emits a 'close' event. - * @return {Promise} + * @return {Promise} - resolves when server is closed */ close() { return new Promise((resolve, reject) => { @@ -128,19 +129,21 @@ class HttpServer { /** * Configures Helmet rules to increase web app security - * @param {string} hostname whitelisted hostname for websocket connection - * @param {list} iframeCsp list of URLs for frame-src CSP - * @param {number} port secure port number + * @param {object} config - configuration of HTTP server + * @param {string} config.hostname whitelisted hostname for websocket connection + * @param {number} config.port secure port number + * @param {list} config.iframeCsp list of URLs for frame-src CSP + * @param {boolean} config.allow allow unsafe-eval in CSP */ - configureHelmet({hostname, port, iframeCsp = [], allow = false}) { + configureHelmet({ hostname, port, iframeCsp = [], allow = false }) { // Sets "X-Frame-Options: DENY" (doesn't allow to be in any iframe) - this.app.use(helmet.frameguard({action: 'deny'})); + this.app.use(helmet.frameguard({ action: 'deny' })); // Sets "Strict-Transport-Security: max-age=5184000 (60 days) (stick to HTTPS) this.app.use(helmet.hsts({ - maxAge: 5184000 + maxAge: 5184000, })); // Sets "Referrer-Policy: same-origin" - this.app.use(helmet.referrerPolicy({policy: 'same-origin'})); + this.app.use(helmet.referrerPolicy({ policy: 'same-origin' })); // Sets "X-XSS-Protection: 1; mode=block" this.app.use(helmet.xssFilter()); // Removes X-Powered-By header @@ -158,7 +161,7 @@ class HttpServer { upgradeInsecureRequests: null, frameSrc: iframeCsp /* eslint-enable */ - } + }, })); } @@ -175,31 +178,31 @@ class HttpServer { } // Router for static files (can grow with addStaticPath) - // eslint-disable-next-line + this.routerStatics = express.Router(); this.addStaticPath(path.join(__dirname, '../../Frontend')); this.addStaticPath(path.join(require.resolve('mithril'), '..'), 'mithril'); this.app.use(this.routerStatics); // Router for public API (can grow with get, post and delete) - // eslint-disable-next-line + this.routerPublic = express.Router(); this.routerPublic.use(async (req, _res, next) => { try { this.jwtAuthenticate(req); - } catch (_e) { + } catch { // User is simply not authenticated } next(); }); - this.routerPublic.use(express.json({limit: this.limit})); // parse json body for API calls + this.routerPublic.use(express.json({ limit: this.limit })); // Parse json body for API calls this.app.use('/api', this.routerPublic); // Router for secure API (can grow with get, post and delete) - // eslint-disable-next-line + this.router = express.Router(); this.router.use(this.jwtVerify.bind(this)); - this.router.use(express.json({limit: this.limit})); // parse json body for API calls + this.router.use(express.json({ limit: this.limit })); // Parse json body for API calls this.app.use('/api', this.router); // Catch-all if no controller handled request @@ -207,7 +210,7 @@ class HttpServer { this.logger.debug(`Page was not found: ${this._parseOriginalUrl(req)}`); res.status(404).json({ error: '404 - Page not found', - message: 'The requested URL was not found on this server.' + message: 'The requested URL was not found on this server.', }); }); @@ -228,7 +231,7 @@ class HttpServer { } else { res.status(500).json({ error: '500 - Server error', - message: 'Something went wrong, please try again or contact an administrator.' + message: 'Something went wrong, please try again or contact an administrator.', }); } }); @@ -243,21 +246,21 @@ class HttpServer { /** * Adds default user details when skipping OAuth flow - * @param {object} req - * @param {object} res + * @param {Request} req - Express Request object + * @param {Response} res - Express Response object * @param {object} next - serves static paths * @return {object} redirection */ addDefaultUserData(req, res, next) { - const query = req.query; + const { query } = req; if (!query.token) { query.personid = 0; query.username = 'anonymous'; query.name = 'Anonymous'; - query.access = 'admin' + query.access = 'admin'; query.token = this.o2TokenService.generateToken(query.personid, query.username, query.name, query.access); - const homeUrlAuthentified = url.format({pathname: '/', query: query}); + const homeUrlAuthentified = url.format({ pathname: '/', query: query }); return res.redirect(homeUrlAuthentified); } return this.ident(req, res, next); @@ -283,12 +286,12 @@ class HttpServer { * Adds GET route using express router, the path will be prefix with "/api" * By default verifies JWT token unless public options is provided * @param {string} path - path that the callback will be bound to - * @param {function} callback - method that handles request and response: function(req, res); + * @param {object} callbacks - method that handles request and response: function(req, res); * token should be passed as req.query.token; * more on req: https://expressjs.com/en/api.html#req * more on res: https://expressjs.com/en/api.html#res - * @param {object} [options={}] - additional options - * @param {boolean} [options.public] - true to remove token verification + * @param {object} [callbacks.options={}] - additional options + * @param {boolean} [callbacks.options.public] - true to remove token verification */ get(path, ...callbacks) { this._all('get', path, ...callbacks); @@ -298,12 +301,12 @@ class HttpServer { * Adds POST route using express router, the path will be prefix with "/api" * By default verifies JWT token unless public options is provided * @param {string} path - path that the callback will be bound to - * @param {function} callback - method that handles request and response: function(req, res); + * @param {function} callbacks - method that handles request and response: function(req, res); * token should be passed as req.query.token; * more on req: https://expressjs.com/en/api.html#req * more on res: https://expressjs.com/en/api.html#res - * @param {object} [options={}] - additional options - * @param {boolean} [options.public] - true to remove token verification + * @param {object} [callbacks.options={}] - additional options + * @param {boolean} [callbacks.options.public] - true to remove token verification */ post(path, ...callbacks) { this._all('post', path, ...callbacks); @@ -313,12 +316,12 @@ class HttpServer { * Adds PUT route using express router, the path will be prefix with "/api" * By default verifies JWT token unless public options is provided * @param {string} path - path that the callback will be bound to - * @param {function} callback - method that handles request and response: function(req, res); + * @param {function} callbacks - method that handles request and response: function(req, res); * token should be passed as req.query.token; * more on req: https://expressjs.com/en/api.html#req * more on res: https://expressjs.com/en/api.html#res - * @param {object} [options={}] - additional options - * @param {boolean} [options.public] - true to remove token verification + * @param {object} [callbacks.options={}] - additional options + * @param {boolean} [callbacks.options.public] - true to remove token verification */ put(path, ...callbacks) { this._all('put', path, ...callbacks); @@ -328,12 +331,12 @@ class HttpServer { * Adds PATCH route using express router, the path will be prefix with "/api" * By default verifies JWT token unless public options is provided * @param {string} path - path that the callback will be bound to - * @param {function} callback - method that handles request and response: function(req, res); + * @param {function} callbacks - method that handles request and response: function(req, res); * token should be passed as req.query.token; * more on req: https://expressjs.com/en/api.html#req * more on res: https://expressjs.com/en/api.html#res - * @param {object} [options={}] - additional options - * @param {boolean} [options.public] - true to remove token verification + * @param {object} [callbacks.options={}] - additional options + * @param {boolean} [callbacks.options.public] - true to remove token verification */ patch(path, ...callbacks) { this._all('patch', path, ...callbacks); @@ -343,12 +346,12 @@ class HttpServer { * Adds DELETE route using express router, the path will be prefix with "/api" * By default verifies JWT token unless public options is provided * @param {string} path - path that the callback will be bound to - * @param {function} callback - method that handles request and response: function(req, res); + * @param {function} callbacks - method that handles request and response: function(req, res); * token should be passed as req.query.token; * more on req: https://expressjs.com/en/api.html#req * more on res: https://expressjs.com/en/api.html#res - * @param {object} [options={}] - additional options - * @param {boolean} [options.public] - true to remove token verification + * @param {object} [callbacks.options={}] - additional options + * @param {boolean} [callbacks.options.public] - true to remove token verification */ delete(path, ...callbacks) { this._all('delete', path, ...callbacks); @@ -359,13 +362,13 @@ class HttpServer { * By default verifies JWT token unless public options is provided * @param {string} method - http method to use * @param {string} path - path that the callback will be bound to - * @param {function[]} callback - method or array of methods that handles request + * @param {function[]} callbacks - method or array of methods that handles request * and response: function(req, res); token should * be passed as req.query.token; * more on req: https://expressjs.com/en/api.html#req * more on res: https://expressjs.com/en/api.html#res - * @param {object} [options={}] - additional options - * @param {boolean} [options.public] - true to remove token verification + * @param {object} [callbacks.options={}] - additional options + * @param {boolean} [callbacks.options.public] - true to remove token verification */ _all(method, path, ...callbacks) { let options = {}; @@ -385,9 +388,9 @@ class HttpServer { * Redirects HTTP to HTTPS. */ enableHttpRedirect() { - this.app.use(function (req, res, next) { + this.app.use((req, res, next) => { if (!req.secure) { - return res.redirect('https://' + req.headers.host + req.url); + return res.redirect(`https://${req.headers.host}${req.url}`); } next(); }); @@ -400,30 +403,30 @@ class HttpServer { * @param {object} req - HTTP request * @param {object} res - HTTP response * @param {object} next - serves static paths when OpenId succeeds - * @return {object} redirects to OpenID flow or displays the page if JWT token is valid */ ident(req, res, next) { - const query = req.query; // User's arguments - const token = req.query.token; + const { query } = req; // User's arguments + const { token } = req.query; if (token) { try { this.o2TokenService.verify(req.query.token); next(); + return; } catch (error) { this.logger.debug(`${error.name} : ${error.message}`); - res.status(403).json({message: error.name}); + res.status(403).json({ message: error.name }); + return; } - } else { - // Redirects to the OpenID flow - const state = Buffer.from(JSON.stringify(query)).toString('base64'); - return res.redirect(this.openid.getAuthUrl(state)); } + // Redirects to the OpenID flow + const state = Buffer.from(JSON.stringify(query)).toString('base64'); + return res.redirect(this.openid.getAuthUrl(state)); } /** * Permit service accounts that holds given role and access from restricted IP address rage - * @param {object} details Account details from unserinfo endpoint + * @param {object} details Account details from unser info endpoint * @param {string} headers HTTP headers including 'X-Forwarded-For' that is actual client IP address set by nginx * @throws {Error} When service account is not allowed to access * @returns true if service account has permission to access the app, false when this is normal account @@ -456,7 +459,7 @@ class HttpServer { details.cern_person_id = 0; } - const {cern_person_id, cern_upn, name} = details; + const { cern_person_id, cern_upn, name } = details; const access = this.authorise(details); // Set token and user details in the query const query = { @@ -473,9 +476,9 @@ class HttpServer { // Concatenates with user query Object.assign(query, userQuery); - res.redirect(url.format({pathname: '/', query: query})); + res.redirect(url.format({ pathname: '/', query: query })); }).catch((reason) => { - this.logger.info('OpenId failed: ' + reason); + this.logger.info(`OpenId failed: ${reason}`); res.status(401).send('OpenId failed'); }); } @@ -509,10 +512,10 @@ class HttpServer { jwtVerify(req, res, next) { try { this.jwtAuthenticate(req); - } catch ({name, message}) { + } catch ({ name, message }) { this.logger.debug(`${name} : ${message}`); - const response = {error: '403 - Json Web Token Error'}; + const response = { error: '403 - Json Web Token Error' }; // Allow for a custom message for known error messages switch (message) { @@ -534,7 +537,7 @@ class HttpServer { /** * Parse the jwt from request and fill request's session and decoded fields accordingly * - * @param req the request + * @param {Request} req - Express Request object * @return {void} resolves once the request is filled with authentication, and reject if jwt verification failed */ jwtAuthenticate(req) { @@ -542,23 +545,24 @@ class HttpServer { req.decoded = data.decoded; req.session = { - personid: parseInt(data.id), + personid: parseInt(data.id, 10), username: data.username, name: data.name, - access: data.access + access: data.access, }; } /** * Given a Request object, returns a new one * with the query parameter, token, removed - * @param {Request} req + * @param {Request} req - Express Request object + * @return {string} the original URL without the token */ _parseOriginalUrl(req) { try { return req.originalUrl.replace(`token=${req.query.token}`, ''); - } catch (error) { - return req.originalUrl + } catch { + return req.originalUrl; } } } diff --git a/Framework/Backend/index.js b/Framework/Backend/index.js index ec58cc666..c72631575 100644 --- a/Framework/Backend/index.js +++ b/Framework/Backend/index.js @@ -19,46 +19,66 @@ const InfoLoggerReceiver = require('./log/InfoLoggerReceiver.js'); const InfoLoggerSender = require('./log/InfoLoggerSender.js'); const Jira = require('./services/jira.js'); const O2TokenService = require('./services/O2TokenService.js'); -const {LogLevel} = require('./log/LogLevel.js'); -const {LogSeverity} = require('./log/LogSeverity.js'); -const {LogManager, Log} = require('./log/LogManager.js'); +const { LogLevel } = require('./log/LogLevel.js'); +const { LogSeverity } = require('./log/LogSeverity.js'); +const { LogManager, Log } = require('./log/LogManager.js'); const MySQL = require('./db/mysql.js'); const NotificationService = require('./services/notification.js'); const WebSocket = require('./websocket/server.js'); const WebSocketMessage = require('./websocket/message.js'); -const {InvalidInputError} = require('./errors/InvalidInputError.js'); -const {NotFoundError} = require('./errors/NotFoundError.js'); -const {ServiceUnavailableError} = require('./errors/ServiceUnavailableError.js'); -const {TimeoutError} = require('./errors/TimeoutError.js'); -const {UnauthorizedAccessError} = require('./errors/UnauthorizedAccessError.js'); -const {grpcErrorToNativeError} = require('./errors/grpcErrorToNativeError.js'); +const { InvalidInputError } = require('./errors/InvalidInputError.js'); +const { NotFoundError } = require('./errors/NotFoundError.js'); +const { ServiceUnavailableError } = require('./errors/ServiceUnavailableError.js'); +const { TimeoutError } = require('./errors/TimeoutError.js'); +const { UnauthorizedAccessError } = require('./errors/UnauthorizedAccessError.js'); +const { grpcErrorToNativeError } = require('./errors/grpcErrorToNativeError.js'); const { updateAndSendExpressResponseFromNativeError, } = require('./errors/updateAndSendExpressResponseFromNativeError.js'); -const {Logger} = require('./log/Logger'); +const { Logger } = require('./log/Logger'); exports.ConsulService = ConsulService; + exports.HttpServer = HttpServer; + exports.InfoLoggerReceiver = InfoLoggerReceiver; + exports.InfoLoggerSender = InfoLoggerSender; + exports.Jira = Jira; + exports.O2TokenService = O2TokenService; + exports.Log = Log; + exports.LogManager = LogManager; + // Use only as type, use LogManager to create loggers exports.Logger = Logger; + exports.LogLevel = LogLevel; + exports.LogSeverity = LogSeverity; + exports.MySQL = MySQL; + exports.NotificationService = NotificationService; + exports.WebSocket = WebSocket; + exports.WebSocketMessage = WebSocketMessage; exports.InvalidInputError = InvalidInputError; + exports.NotFoundError = NotFoundError; + exports.ServiceUnavailableError = ServiceUnavailableError; + exports.TimeoutError = TimeoutError; + exports.UnauthorizedAccessError = UnauthorizedAccessError; + exports.grpcErrorToNativeError = grpcErrorToNativeError; + exports.updateAndSendExpressResponseFromNativeError = updateAndSendExpressResponseFromNativeError; diff --git a/Framework/Backend/log/InfoLoggerMessage.js b/Framework/Backend/log/InfoLoggerMessage.js index 7d377759f..9b1510a30 100644 --- a/Framework/Backend/log/InfoLoggerMessage.js +++ b/Framework/Backend/log/InfoLoggerMessage.js @@ -12,8 +12,8 @@ * or submit itself to any jurisdiction. */ -const {LogLevel} = require('./LogLevel.js'); -const {LOG_SEVERITIES, LogSeverity} = require('./LogSeverity.js'); +const { LogLevel } = require('./LogLevel.js'); +const { LOG_SEVERITIES, LogSeverity } = require('./LogSeverity.js'); const DEFAULT_SEVERITY = LogSeverity.INFO; const DEFAULT_LEVEL = LogLevel.DEVELOPER; @@ -39,7 +39,6 @@ const DEFAULT_FACILITY = 'gui'; * @docs https://github.com/AliceO2Group/InfoLogger/blob/master/doc/README.md */ class InfoLoggerMessage { - /** * Construct a default InfoLoggerMessage */ @@ -66,7 +65,7 @@ class InfoLoggerMessage { log._severity = logObject.severity && LOG_SEVERITIES.includes(logObject.severity) ? logObject.severity : LogSeverity.INFO; - log._level = parseInt(logObject?.level) || LogLevel.DEVELOPER; + log._level = parseInt(logObject?.level, 10) || LogLevel.DEVELOPER; log._system = logObject.system ?? DEFAULT_SYSTEM; log._facility = logObject.facility ?? DEFAULT_FACILITY; log._environmentId = logObject.environmentId ?? logObject.partition; @@ -83,8 +82,10 @@ class InfoLoggerMessage { */ getComponentsOfMessage() { const components = [ - `-oSeverity=${this._severity}`, `-oLevel=${this._level}`, - `-oSystem=${this._system}`, `-oFacility=${this._facility}`, + `-oSeverity=${this._severity}`, + `-oLevel=${this._level}`, + `-oSystem=${this._system}`, + `-oFacility=${this._facility}`, ]; if (this._environmentId) { components.push(`-oPartition=${this._environmentId}`); @@ -101,8 +102,8 @@ class InfoLoggerMessage { /** * Replace all occurrences of new lines, tabs or groups of 4 spaces with an empty space - * @param {Object|Error|String} log - * @return {String} + * @param {Object|Error|String} log - the log to be cleaned + * @return {string} - the cleaned log */ static _removeNewLinesAndTabs(log) { try { @@ -112,7 +113,7 @@ class InfoLoggerMessage { return JSON.stringify(log).replace(/ {4}|[\t\n\r]/gm, ' '); } return log.replace(/ {4}|[\t\n\r]/gm, ' '); - } catch (error) { + } catch { return ''; } } diff --git a/Framework/Backend/log/InfoLoggerReceiver.js b/Framework/Backend/log/InfoLoggerReceiver.js index 3d2ecf14c..b2af1700c 100644 --- a/Framework/Backend/log/InfoLoggerReceiver.js +++ b/Framework/Backend/log/InfoLoggerReceiver.js @@ -10,13 +10,13 @@ * In applying this license CERN does not waive the privileges and immunities * granted to it by virtue of its status as an Intergovernmental Organization * or submit itself to any jurisdiction. -*/ + */ const net = require('net'); const EventEmitter = require('events'); const protocols = require('./infologger-protocols.js'); -const {LogManager} = require('./LogManager'); +const { LogManager } = require('./LogManager'); /** * @class InfoLoggerReceiver @@ -93,7 +93,7 @@ class InfoLoggerReceiver extends EventEmitter { } this.isConnected = false; this.client.end(); - this.client = null; // gc + this.client = null; // Gc } /** @@ -104,7 +104,7 @@ class InfoLoggerReceiver extends EventEmitter { onData(data) { let dataString = this.buffer + data.toString(); this.buffer = ''; - // detect whether the last log is chopped in the middle + // Detect whether the last log is chopped in the middle if (dataString[dataString.length - 1] !== '\n') { const indexLast = dataString.lastIndexOf('\n'); this.buffer = dataString.substring(indexLast); @@ -116,16 +116,18 @@ class InfoLoggerReceiver extends EventEmitter { if (!message) { continue; } + /** - * Message event containing log properties - * - * @event LiveDataSource#message - * @type {object} - */ - this.emit('message', this.parse(message + '\n')); + * Message event containing log properties + * + * @event LiveDataSource#message + * @type {object} + */ + this.emit('message', this.parse(`${message}\n`)); } } + // eslint-disable-next-line jsdoc/require-returns-check /** * Parse an input string frame to corresponding object * Empty fields are ignored. @@ -133,8 +135,8 @@ class InfoLoggerReceiver extends EventEmitter { * *1.4#I##1505140368.399439#aido2db##143388#root#########test Mon Sep 11 16:32:48 CEST 2017 * Example of output: * {severity: 'I', hostname: 'aido2db', ...} - * @param {string} frame - * @return {Object} + * @param {string} frame - frame that is to be parsed + * @return {object} - parsed object */ parse(frame) { // Check frame integrity (header and footer) diff --git a/Framework/Backend/log/InfoLoggerSender.js b/Framework/Backend/log/InfoLoggerSender.js index da995a453..04682a539 100644 --- a/Framework/Backend/log/InfoLoggerSender.js +++ b/Framework/Backend/log/InfoLoggerSender.js @@ -12,11 +12,11 @@ * or submit itself to any jurisdiction. */ -const {access, constants: {X_OK}} = require('fs'); -const {execFile} = require('child_process'); +const { access, constants: { X_OK } } = require('fs'); +const { execFile } = require('child_process'); const InfoLoggerMessage = require('./InfoLoggerMessage.js'); -const {LogLevel} = require('./LogLevel.js'); -const {LogSeverity} = require('./LogSeverity.js'); +const { LogLevel } = require('./LogLevel.js'); +const { LogSeverity } = require('./LogSeverity.js'); /** * Sends logs as InfoLogger objects to InfoLoggerD over UNIX named socket @@ -24,6 +24,7 @@ const {LogSeverity} = require('./LogSeverity.js'); */ class InfoLoggerSender { /** + * Constructor for InfoLoggerSender expecting a winston instance * @param {import('winston').Logger} winston - local winston instance object */ constructor(winston) { @@ -31,13 +32,13 @@ class InfoLoggerSender { this.winston = winston; const label = 'gui/infologger'; - // for security reasons this path is hardcoded + // For security reasons this path is hardcoded this._PATH = '/opt/o2-InfoLogger/bin/o2-infologger-log'; access(this._PATH, X_OK, (err) => { if (err) { - this.winston.debug({message: 'InfoLogger executable not found', label}); + this.winston.debug({ message: 'InfoLogger executable not found', label }); } else { - this.winston.debug({message: 'Created instance of InfoLogger sender', label}); + this.winston.debug({ message: 'Created instance of InfoLogger sender', label }); this._isConfigured = true; } }); @@ -67,24 +68,28 @@ class InfoLoggerSender { } /** - * @deprecated * Send a message to InfoLogger with certain fields filled. * @param {string} log - log message - * @param {string} severity - one of InfoLogger supported severities {@see LogSeverity} + * @param {LogSeverity} severity - one of InfoLogger supported severities {@see LogSeverity} * @param {string} facility - the name of the module/library injecting the message * @param {number} level - visibility of the message {@see LogLevel} + * @deprecated */ send(log, severity = LogSeverity.INFO, facility = '', level = LogLevel.MAX) { if (this._isConfigured) { log = InfoLoggerMessage._removeNewLinesAndTabs(log); execFile(this._PATH, [ - `-oSeverity=${severity}`, `-oFacility=${facility}`, `-oSystem=GUI`, `-oLevel=${level}`, `${log}`, + `-oSeverity=${severity}`, + `-oFacility=${facility}`, + '-oSystem=GUI', + `-oLevel=${level}`, + `${log}`, ], (error, _, stderr) => { if (error) { - this.winston.debug({message: `Impossible to write a log to InfoLogger due to: ${error}`, label: facility}); + this.winston.debug({ message: `Impossible to write a log to InfoLogger due to: ${error}`, label: facility }); } if (stderr) { - this.winston.debug({message: `Impossible to write a log to InfoLogger due to: ${stderr}`, label: facility}); + this.winston.debug({ message: `Impossible to write a log to InfoLogger due to: ${stderr}`, label: facility }); } }); } diff --git a/Framework/Backend/log/LogManager.js b/Framework/Backend/log/LogManager.js index 70cbe0dbd..7971e02f1 100644 --- a/Framework/Backend/log/LogManager.js +++ b/Framework/Backend/log/LogManager.js @@ -1,6 +1,6 @@ const WinstonWrapper = require('./WinstonWrapper'); const InfoLoggerSender = require('./InfoLoggerSender'); -const {Logger} = require('./Logger'); +const { Logger } = require('./Logger'); /** * Utility class for logging @@ -40,7 +40,7 @@ class LogManager { * @return {Logger} the logger instance */ static getLogger(label) { - return new Logger(label, {winston: LogManager.winston, infologger: LogManager.infologger}); + return new Logger(label, { winston: LogManager.winston, infologger: LogManager.infologger }); } /** @@ -51,7 +51,7 @@ class LogManager { static get winston() { if (!LogManager._winston) { LogManager._winston = new WinstonWrapper(); - LogManager._winston.instance.info({message: 'Default console logger instantiated', label: ''}); + LogManager._winston.instance.info({ message: 'Default console logger instantiated', label: '' }); } return LogManager._winston; } @@ -72,9 +72,10 @@ class LogManager { exports.LogManager = LogManager; /** - * @deprecated use {@link LogManager.getLogger} - * @param label the logger's label + * Deprecated constructor for Log class + * @param {string} label - the logger's label * @constructor + * @deprecated use {@link LogManager.getLogger} */ function Log(label) { this.label = label; diff --git a/Framework/Backend/log/LogSeverity.js b/Framework/Backend/log/LogSeverity.js index 345e5d63a..8b3a6ebaf 100644 --- a/Framework/Backend/log/LogSeverity.js +++ b/Framework/Backend/log/LogSeverity.js @@ -29,4 +29,4 @@ const LOG_SEVERITIES = Object.values(LogSeverity); exports.LogSeverity = LogSeverity; -exports.LOG_SEVERITIES = LOG_SEVERITIES; \ No newline at end of file +exports.LOG_SEVERITIES = LOG_SEVERITIES; diff --git a/Framework/Backend/log/Logger.js b/Framework/Backend/log/Logger.js index 8941282f7..d09a5b335 100644 --- a/Framework/Backend/log/Logger.js +++ b/Framework/Backend/log/Logger.js @@ -13,8 +13,8 @@ */ const InfoLoggerMessage = require('./InfoLoggerMessage.js'); -const {LogLevel} = require('./LogLevel.js'); -const {LogSeverity} = require('./LogSeverity.js'); +const { LogLevel } = require('./LogLevel.js'); +const { LogSeverity } = require('./LogSeverity.js'); /** * Handles logging, prints out in console, saves to file or sends to central InfoLogger instance @@ -28,7 +28,7 @@ class Logger { static maximumInfoLoggerLevel = LogLevel.DEVELOPER; /** - * @constructor + * Constructor for the logger class * @param {string} [label=''] - the logger's label * @param {object} [delegates] - delegates logger * @param {WinstonWrapper} [delegates.winston] - winston wrapper @@ -37,7 +37,7 @@ class Logger { constructor(label, delegates) { this.label = label ?? ''; - const {winston, infologger} = delegates ?? {}; + const { winston, infologger } = delegates ?? {}; this._winston = winston; this._infologger = infologger; } @@ -49,9 +49,9 @@ class Logger { * @param {Partial} [options] - log options. If omitted, log will be sent to local file only */ debugMessage(message, options) { - this._winston.instance.debug({message, label: this.label}); + this._winston.instance.debug({ message, label: this.label }); - this._sendToInfoLogger(message, {...options, severity: LogSeverity.DEBUG}); + this._sendToInfoLogger(message, { ...options, severity: LogSeverity.DEBUG }); } /** @@ -71,9 +71,9 @@ class Logger { * @param {Partial} [options] - log options. If omitted, log will be sent to local file only */ infoMessage(message, options) { - this._winston.instance.info({message, label: this.label}); + this._winston.instance.info({ message, label: this.label }); - this._sendToInfoLogger(message, {...options, severity: LogSeverity.INFO}); + this._sendToInfoLogger(message, { ...options, severity: LogSeverity.INFO }); } /** @@ -84,7 +84,7 @@ class Logger { * @deprecated use {@link Logger.infoMessage} */ info(log, level = LogLevel.DEVELOPER) { - this.infoMessage(log, {level}); + this.infoMessage(log, { level }); } /** @@ -93,9 +93,9 @@ class Logger { * @param {Partial} [options] - log options. If omitted, log will be sent to local file only */ warnMessage(message, options) { - this._winston.instance.warn({message, label: this.label}); + this._winston.instance.warn({ message, label: this.label }); - this._sendToInfoLogger(message, {...options, severity: LogSeverity.WARNING}); + this._sendToInfoLogger(message, { ...options, severity: LogSeverity.WARNING }); } /** @@ -106,7 +106,7 @@ class Logger { * @deprecated use {@link Logger.warnMessage} */ warn(log, level = LogLevel.DEVELOPER) { - this.warnMessage(log, {level}); + this.warnMessage(log, { level }); } /** @@ -115,9 +115,9 @@ class Logger { * @param {Partial} [options] - log options. If omitted, log will be sent to local file only */ errorMessage(message, options) { - this._winston.instance.error({message, label: this.label}); + this._winston.instance.error({ message, label: this.label }); - this._sendToInfoLogger(message, {...options, severity: LogSeverity.ERROR}); + this._sendToInfoLogger(message, { ...options, severity: LogSeverity.ERROR }); } /** @@ -128,7 +128,7 @@ class Logger { * @deprecated use {@link Logger.errorMessage} */ error(log, level = LogLevel.DEVELOPER) { - this.errorMessage(log, {level}); + this.errorMessage(log, { level }); } /** @@ -136,7 +136,7 @@ class Logger { * @param {Error} error - error with stack field */ trace(error) { - this._winston.instance.verbose({message: error.stack, label: this.label}); + this._winston.instance.verbose({ message: error.stack, label: this.label }); } /** diff --git a/Framework/Backend/log/WinstonWrapper.js b/Framework/Backend/log/WinstonWrapper.js index f7b9f7883..d3df32bdd 100644 --- a/Framework/Backend/log/WinstonWrapper.js +++ b/Framework/Backend/log/WinstonWrapper.js @@ -10,9 +10,9 @@ * In applying this license CERN does not waive the privileges and immunities * granted to it by virtue of its status as an Intergovernmental Organization * or submit itself to any jurisdiction. -*/ + */ -const {createLogger, format, transports: {Console, File}} = require('winston'); +const { createLogger, format, transports: { Console, File } } = require('winston'); /** * Creates AliceO2 Winston Wrapper @@ -27,7 +27,7 @@ class WinstonWrapper { this._instance = createLogger({ transports: [ this._consoleTransport(config?.console), - ...(config?.file?.name ? [this._fileTransport(config.file)] : []), + ...config?.file?.name ? [this._fileTransport(config.file)] : [], ], exitOnError: true, }); @@ -37,11 +37,13 @@ class WinstonWrapper { * Configures the console formatter and returns a new instance of it * Messages will be prefixed with a timestamp and a label * @example + * @param {object} [console] - configuration for console transport + * @param {boolean} [console.systemd] - if true, log will be formatted for systemd + * @param {string} [console.level] - log level for console transport default to debug * // 2022-10-22T10:27:53.903Z [test/service] debug: Created default instance of console logger - * @param {{systemd: string, level: string}} - object which may contain console transport configuration fields * @returns {winston.transports.ConsoleTransportInstance} */ - _consoleTransport(console = {systemd: undefined, level: 'debug'}) { + _consoleTransport(console = { systemd: undefined, level: 'debug' }) { // Mapping between winston levels and journalctl priorities const systemdPr = { debug: '<7>', @@ -64,31 +66,33 @@ class WinstonWrapper { format: format.combine( format.timestamp(), format.colorize(), - formatter - ) + formatter, + ), }); } /** * Configures the file transporter and returns a new instance of it * Messages will be prefixed with a timestamp and printed using the winston formatter - * @param {{name: string, level: string}} - object which may contain file transport configuration fields + * @param {object} [configuration] - object which may contain file transport configuration fields + * @param {string} [configuration.name] - name of the file whwre logs will be stored + * @param {string} [configuration.level] - log level for file transport default to info * @returns {winston.transports.FileTransportInstance} */ - _fileTransport({name, level = 'info'}) { + _fileTransport({ name, level = 'info' }) { return new File({ level, filename: name, format: format.combine( format.timestamp(), - format.prettyPrint() - ) + format.prettyPrint(), + ), }); } /** * Returns an instance of AliceO2 Winston Wrapper - * @return {import('winston').Logger} + * @return {import('winston').Logger} - instance of the O2 Winston Wrapper */ get instance() { return this._instance; diff --git a/Framework/Backend/log/infologger-protocols.js b/Framework/Backend/log/infologger-protocols.js index aec19e111..b25de2c2c 100644 --- a/Framework/Backend/log/infologger-protocols.js +++ b/Framework/Backend/log/infologger-protocols.js @@ -10,50 +10,50 @@ * In applying this license CERN does not waive the privileges and immunities * granted to it by virtue of its status as an Intergovernmental Organization * or submit itself to any jurisdiction. -*/ + */ module.exports = [ { version: '1.3', fields: [ - {name: 'severity', type: String}, - {name: 'level', type: Number}, - {name: 'timestamp', type: Number}, - {name: 'hostname', type: String}, - {name: 'rolename', type: String}, - {name: 'pid', type: Number}, - {name: 'username', type: String}, - {name: 'system', type: String}, - {name: 'facility', type: String}, - {name: 'detector', type: String}, - {name: 'partition', type: String}, - {name: 'dest', type: String}, - {name: 'run', type: Number}, - {name: 'errcode', type: Number}, - {name: 'errline', type: Number}, - {name: 'errsource', type: String}, - {name: 'message', type: String} - ] + { name: 'severity', type: String }, + { name: 'level', type: Number }, + { name: 'timestamp', type: Number }, + { name: 'hostname', type: String }, + { name: 'rolename', type: String }, + { name: 'pid', type: Number }, + { name: 'username', type: String }, + { name: 'system', type: String }, + { name: 'facility', type: String }, + { name: 'detector', type: String }, + { name: 'partition', type: String }, + { name: 'dest', type: String }, + { name: 'run', type: Number }, + { name: 'errcode', type: Number }, + { name: 'errline', type: Number }, + { name: 'errsource', type: String }, + { name: 'message', type: String }, + ], }, { version: '1.4', fields: [ - {name: 'severity', type: String}, - {name: 'level', type: Number}, - {name: 'timestamp', type: Number}, - {name: 'hostname', type: String}, - {name: 'rolename', type: String}, - {name: 'pid', type: Number}, - {name: 'username', type: String}, - {name: 'system', type: String}, - {name: 'facility', type: String}, - {name: 'detector', type: String}, - {name: 'partition', type: String}, - {name: 'run', type: Number}, - {name: 'errcode', type: Number}, - {name: 'errline', type: Number}, - {name: 'errsource', type: String}, - {name: 'message', type: String} - ] - } + { name: 'severity', type: String }, + { name: 'level', type: Number }, + { name: 'timestamp', type: Number }, + { name: 'hostname', type: String }, + { name: 'rolename', type: String }, + { name: 'pid', type: Number }, + { name: 'username', type: String }, + { name: 'system', type: String }, + { name: 'facility', type: String }, + { name: 'detector', type: String }, + { name: 'partition', type: String }, + { name: 'run', type: Number }, + { name: 'errcode', type: Number }, + { name: 'errline', type: Number }, + { name: 'errsource', type: String }, + { name: 'message', type: String }, + ], + }, ]; diff --git a/Framework/Backend/services/O2TokenService.js b/Framework/Backend/services/O2TokenService.js index cf7c8655c..d0c359313 100644 --- a/Framework/Backend/services/O2TokenService.js +++ b/Framework/Backend/services/O2TokenService.js @@ -10,10 +10,10 @@ * In applying this license CERN does not waive the privileges and immunities * granted to it by virtue of its status as an Intergovernmental Organization * or submit itself to any jurisdiction. -*/ + */ const jwt = require('jsonwebtoken'); -const {randomBytes} = require('crypto'); +const { randomBytes } = require('crypto'); /** * Provides JSON Web Token functionality such as token generation and verification with `jsonwebtoken` library @@ -42,9 +42,9 @@ class O2TokenService { * @return {string} generated token */ generateToken(personid, username, name, access = '') { - return jwt.sign({id: personid, username, name, access}, this._secret, { + return jwt.sign({ id: personid, username, name, access }, this._secret, { expiresIn: this._expiration, - issuer: this._issuer + issuer: this._issuer, }); } @@ -52,11 +52,11 @@ class O2TokenService { * Attempts to decrypt passed token to verify its validity. * If token is valid, decode data from it will be returned, else an error is thrown * @param {string} token - token to be verified - * @return {Object>} whether operation was successful, if so decoded data are passed as well + * @return {object} whether operation was successful, if so decoded data are passed as well * @throws {Error} - if token, secret or issuer are invalid */ verify(token) { - return jwt.verify(token, this._secret, {issuer: this._issuer}) + return jwt.verify(token, this._secret, { issuer: this._issuer }); } } diff --git a/Framework/Backend/services/consul.service.js b/Framework/Backend/services/consul.service.js index 5647636e5..adeb2398f 100644 --- a/Framework/Backend/services/consul.service.js +++ b/Framework/Backend/services/consul.service.js @@ -10,7 +10,7 @@ * In applying this license CERN does not waive the privileges and immunities * granted to it by virtue of its status as an Intergovernmental Organization * or submit itself to any jurisdiction. -*/ + */ const http = require('http'); @@ -20,7 +20,7 @@ const http = require('http'); class ConsulService { /** * Setup Consul configuration - * @param {JSON} config + * @param {object} config - configuration for Consul */ constructor(config) { if (!config) { @@ -43,7 +43,7 @@ class ConsulService { /** * Returns a promise with regards to the status of the consul leader - * @return {Promise} + * @return {Promise} - a JSON object containing the leader status */ async getConsulLeaderStatus() { return this.httpJson(this.leaderPath); @@ -53,7 +53,7 @@ class ConsulService { * Method to return a promise containing all services stored in Consul * * a JSON of Objects representing all services with their metadata * * an error if request was not successful - * @return {Promise} + * @return {Promise} - a JSON object containing all services */ async getServices() { return this.httpJson(this.servicesPath); @@ -62,29 +62,29 @@ class ConsulService { /** * Method to return a Promise containing: * * an array of strings representing all keys in Consul store if request is successful - * @return {Promise., Error>} + * @return {Promise., Error>} - an array of strings representing all keys in Consul store */ async getKeys() { - return this.httpJson(this.kvPath + '?keys=true'); + return this.httpJson(`${this.kvPath}?keys=true`); } /** * Method to return a Promise containing: * * an array of strings representing all keys that starts with the provided `keyPrefix` * @param {string} keyPrefix - containing the prefix of the keys requested - * @return {Promise., Error>} + * @return {Promise., Error>} - an array of strings representing all keys that starts with the provided `keyPrefix` */ async getKeysByPrefix(keyPrefix) { keyPrefix = this.parseKey(keyPrefix); - const getPath = this.kvPath + keyPrefix + '/?keys=true'; + const getPath = `${this.kvPath + keyPrefix}/?keys=true`; return this.httpJson(getPath); } /** * Method to return a Promise containing: * * a JSON object containing the Value and metadata stored for the specified key; If key is not found 404 is returned - * @param {string} key - * @return {Promise.} + * @param {string} key - key to search for + * @return {Promise.} - a JSON object containing the Value and metadata stored for the specified key */ async getValueObjectByKey(key) { key = this.parseKey(key); @@ -95,24 +95,24 @@ class ConsulService { /** * Method to return a Promise containing: * * the raw value stored for the requested key; If key is not found 404 is returned - * @param {string} key - * @return {Promise.} + * @param {string} key - key to search for + * @return {Promise.} - the raw value stored for the requested key */ async getOnlyRawValueByKey(key) { key = this.parseKey(key); - const getPath = this.kvPath + key + '?raw=true'; + const getPath = `${this.kvPath + key}?raw=true`; return this.httpJson(getPath); } /** * Method to return a Promise containing: * * * an `Array` containing the value and metadata stored for the objects with the requested keyPrefix; - * @param {string} keyPrefix - * @return {Promise., Error>} + * @param {string} keyPrefix - keyPrefix to search for + * @return {Promise., Error>} - an `Array` containing the value and metadata stored for the objects with keyPrefix */ async getValuesByKeyPrefix(keyPrefix) { keyPrefix = this.parseKey(keyPrefix); - const getPath = this.kvPath + keyPrefix + '?recurse=true'; + const getPath = `${this.kvPath + keyPrefix}?recurse=true`; return this.httpJson(getPath); } @@ -120,12 +120,12 @@ class ConsulService { * Method to return a Promise containing: * * * an `Array` containing the raw value stored for the objects with the requested keyPrefix; * * an error if request was not successful - * @param {string} keyPrefix - * @return {Promise., Error>} + * @param {string} keyPrefix - keyPrefix to search for + * @return {Promise., Error>} - an `Array` containing the raw value stored for the objects with keyPrefix */ async getOnlyRawValuesByKeyPrefix(keyPrefix) { keyPrefix = this.parseKey(keyPrefix); - const getPath = this.kvPath + keyPrefix + '?recurse=true'; + const getPath = `${this.kvPath + keyPrefix}?recurse=true`; return this.httpJson(getPath).then((data) => { const response = {}; data.forEach((object) => { @@ -145,8 +145,8 @@ class ConsulService { * and use transactions to update or set new keys in Consul KV Store * Will return Promise.Resolve() with ok if all transaction was done * or false if at least one failed - * @param {Array} list - * @return {Promise.} + * @param {Array} list - list of key value pairs + * @return {Promise.} - JSON object with the status of the transaction */ async putListOfKeyValues(list) { const consulBuiltList = this._mapToConsulKVObjectsLists(list); @@ -155,18 +155,18 @@ class ConsulService { try { const requestOptions = this._getRequestOptionsPUT(this.txnPath, list); await this.httpJson(this.txnPath, requestOptions, list); - } catch (error) { + } catch { allPut = false; } })); - return {allPut: allPut}; + return { allPut: allPut }; } /** * Util to get/put JSON data (parsed) from Consul server * @param {string} path - path to Consul server - * @param {JSON} requestOptions - * @param {JSON} data + * @param {object} requestOptions - http request options + * @param {object} data - data to send in GET.PUT request * @return {Promise.} JSON response */ async httpJson(path, requestOptions, data) { @@ -175,20 +175,20 @@ class ConsulService { hostname: this.hostname, port: this.port, path: path, - qs: {keys: true}, + qs: { keys: true }, method: 'GET', - headers: {Accept: 'application/json'} + headers: { Accept: 'application/json' }, }; /** * Generic handler for client http requests, * buffers response, checks status code and parses JSON - * @param {Response} response - * @return {Promise.} + * @param {Response} response - HTTP express response object + * @return {void} */ const requestHandler = (response) => { if (response.statusCode < 200 || response.statusCode > 299) { - reject(new Error('Non-2xx status code: ' + response.statusCode)); + reject(new Error(`Non-2xx status code: ${response.statusCode}`)); } const bodyChunks = []; response.on('data', (chunk) => bodyChunks.push(chunk)); @@ -196,11 +196,11 @@ class ConsulService { try { const body = JSON.parse(bodyChunks.join('')); resolve(body); - } catch (e) { + } catch { reject(new Error('Unable to parse JSON')); } }); - } + }; const request = http.request(reqOptions, requestHandler); request.on('error', (err) => reject(err)); @@ -217,8 +217,9 @@ class ConsulService { /** * Build a JSON with request options needed for PUT request - * @param {JSON} data - * @return {JSON} + * @param {string} path - path to for request to Consul Server + * @param {object} data - data to send + * @return {object} - request options */ _getRequestOptionsPUT(path, data) { if (typeof data !== 'string') { @@ -227,19 +228,19 @@ class ConsulService { return { hostname: this.hostname, port: this.port, - path: path, + path, method: 'PUT', headers: { 'Content-Type': 'application/json', - 'Content-Length': data.length - } + 'Content-Length': data.length, + }, }; } /** * Method to check for and remove any `/` from the start and end of a key/keyPrefix * @param {string} key - key or keyPrefix to check - * @return {string} + * @return {string} - key or keyPrefix without `/` at the start and end */ parseKey(key) { if (key.charAt(0) === '/') { @@ -256,20 +257,20 @@ class ConsulService { * These pairs will than be placed in batches due to the fact that a transaction * accepts maximum 64 elements * https://www.consul.io/api/txn - * @param {Array<>} list - * @return {Array>} + * @param {Array} list - list of KV pairs + * @return {Array>} - list of transactions */ _mapToConsulKVObjectsLists(list) { const consulList = []; let transactionList = []; list.forEach((kvPair) => { - const key = Object.keys(kvPair)[0]; + const [key] = Object.keys(kvPair); const consulObj = { KV: { Verb: 'set', Key: key, - Value: Buffer.from(kvPair[key]).toString('base64') - } + Value: Buffer.from(kvPair[key]).toString('base64'), + }, }; transactionList.push(consulObj); if (transactionList.length >= 64) { diff --git a/Framework/Backend/services/jira.js b/Framework/Backend/services/jira.js index fe17e7db6..bd53f9228 100644 --- a/Framework/Backend/services/jira.js +++ b/Framework/Backend/services/jira.js @@ -10,16 +10,17 @@ * In applying this license CERN does not waive the privileges and immunities * granted to it by virtue of its status as an Intergovernmental Organization * or submit itself to any jurisdiction. -*/ + */ const https = require('https'); -const {LogManager} = require('../log/LogManager'); +const { LogManager } = require('../log/LogManager'); /** * Handles creating JIRA issues */ class Jira { /** + * Constructor for Jira Service * @param {object} config - JIRA configuration including URL, service account and project ID */ constructor(config) { @@ -41,7 +42,7 @@ class Jira { this.accountPass = config.serviceAccount.pass; this.projectId = config.projectId; this.issueTypes = { - bug: 1 + bug: 1, }; this.logger = LogManager.getLogger(`${process.env.npm_config_log_label ?? 'framework'}/jira`); @@ -54,17 +55,17 @@ class Jira { async createIssue(postData) { const requestOptions = { method: 'POST', - auth: this.accountUser + ':' + this.accountPass, + auth: `${this.accountUser}:${this.accountPass}`, headers: { 'Content-Type': 'application/json', Accept: 'application/json', - 'Content-Length': Buffer.byteLength(postData) - } + 'Content-Length': Buffer.byteLength(postData), + }, }; return new Promise((resolve, reject) => { - const requestHandler = (response) => { // eslint-disable-line require-jsdoc + const requestHandler = (response) => { if (response.statusCode < 200 || response.statusCode > 299) { - reject(new Error('Non-2xx status code: ' + response.statusCode)); + reject(new Error(`Non-2xx status code: ${response.statusCode}`)); return; } const bodyChunks = []; @@ -73,7 +74,7 @@ class Jira { try { const body = JSON.parse(bodyChunks.join('')); resolve(body); - } catch (e) { + } catch { reject(new Error('Unable to parse JSON')); } }); @@ -99,26 +100,26 @@ class Jira { this.logger.warn('Creating bug issue failed: undefined arguments'); return Promise.reject(new Error('Invalid parameters passed')); } - const issue = JSON.stringify( - { - fields: { - issuetype: { - id: this.issueTypes.bug - }, - project: { - id: this.projectId - }, - summary: summary, - description: description, - reporter: { - name: reporter - }, - assignee: { - name: assignee - } - } - }); + const issue = JSON.stringify({ + fields: { + issuetype: { + id: this.issueTypes.bug, + }, + project: { + id: this.projectId, + }, + summary: summary, + description: description, + reporter: { + name: reporter, + }, + assignee: { + name: assignee, + }, + }, + }); return this.createIssue(issue); } } + module.exports = Jira; diff --git a/Framework/Backend/services/notification.js b/Framework/Backend/services/notification.js index c93283d7f..475f4f172 100644 --- a/Framework/Backend/services/notification.js +++ b/Framework/Backend/services/notification.js @@ -10,11 +10,11 @@ * In applying this license CERN does not waive the privileges and immunities * granted to it by virtue of its status as an Intergovernmental Organization * or submit itself to any jurisdiction. -*/ + */ -const { Kafka, logLevel } = require('kafkajs') +const { Kafka, logLevel } = require('kafkajs'); const WebSocketMessage = require('../websocket/message.js'); -const {LogManager} = require('../log/LogManager'); +const { LogManager } = require('../log/LogManager'); /** * Gateway for all Kafka notification service @@ -37,8 +37,8 @@ class NotificationService { this.kafka = new Kafka({ clientId: 'webui', brokers: config.brokers, - retry: {retries: 3}, - logLevel: logLevel.NOTHING + retry: { retries: 3 }, + logLevel: logLevel.NOTHING, }); this.admin = this.kafka.admin(); @@ -49,14 +49,14 @@ class NotificationService { /** * Check if Kafka was correctly configured - * @return {boolean} States wheather service is correctly configured + * @return {boolean} States whether service is correctly configured */ isConfigured() { - return (this.kafka !== undefined && this.admin !== undefined); + return this.kafka !== undefined && this.admin !== undefined; } /** - * Provides healthstatus of Kafka cluster + * Provides health status of Kafka cluster * @returns {Promise} */ async health() { @@ -72,7 +72,7 @@ class NotificationService { async send(message = undefined) { const producer = this.kafka.producer(); await producer.connect(); - await producer.send({topic: this.topic, messages: [{value: JSON.stringify(message)}]}); + await producer.send({ topic: this.topic, messages: [{ value: JSON.stringify(message) }] }); await producer.disconnect(); } @@ -83,16 +83,14 @@ class NotificationService { */ async proxyWebNotificationToWs(webSocket) { this.webSocket = webSocket; - this.consumer = this.kafka.consumer({groupId: 'webnotification-group'}); + this.consumer = this.kafka.consumer({ groupId: 'webnotification-group' }); this.logger.info('Listening for notifications'); await this.consumer.connect(); - await this.consumer.subscribe({topic: 'webnotification', fromBeginning: false}); - await this.consumer.run({eachMessage: async ({topic, partition, message}) => { + await this.consumer.subscribe({ topic: 'webnotification', fromBeginning: false }); + await this.consumer.run({ eachMessage: async ({ topic, partition, message }) => { this.logger.debug(`Received message on ${topic} topic from ${partition} partition`); - this.webSocket.broadcast( - new WebSocketMessage().setCommand('notification').setPayload(message.value.toString()) - ); - }}); + this.webSocket.broadcast(new WebSocketMessage().setCommand('notification').setPayload(message.value.toString())); + } }); } /** diff --git a/Framework/Backend/test/config.js b/Framework/Backend/test/config.js index 9d6aaae3f..02267eb0e 100644 --- a/Framework/Backend/test/config.js +++ b/Framework/Backend/test/config.js @@ -1,47 +1,47 @@ module.exports = { jwt: { - secret: "", - issuer: "alice-o2-gui", - expiration: "60s", - maxAge: "2m" + secret: '', + issuer: 'alice-o2-gui', + expiration: '60s', + maxAge: '2m', }, openId: { - secret: "", - id: "", - redirect_uri: "https://redirect.uri/callback", - well_known: "http://localhost/.well-known/openid-configuration'" + secret: '', + id: '', + redirect_uri: 'https://redirect.uri/callback', + well_known: "http://localhost/.well-known/openid-configuration'", }, http: { port: 8181, portSecure: 8443, - key: "test.key", - cert: "test.pem", - tls: false + key: 'test.key', + cert: 'test.pem', + tls: false, }, mysql: { - host: "127.0.0.1", - user: "root", - password: "", - database: "INFOLOGGER", - port: 3306 + host: '127.0.0.1', + user: 'root', + password: '', + database: 'INFOLOGGER', + port: 3306, }, log: { winston: { file: { - name: "./Backend/test/log/error.log", - level: "error" + name: './Backend/test/log/error.log', + level: 'error', }, console: { - level: "debug" - } + level: 'debug', + }, }, - infologger: false + infologger: false, }, consul: { - hostname: "localhost", - port: 8080 + hostname: 'localhost', + port: 8080, }, notification: { - brokers: ["localhost:9092"] - } + brokers: ['localhost:9092'], + }, }; diff --git a/Framework/Backend/test/errors/mocha-grpcErrorToNativeError.js b/Framework/Backend/test/errors/mocha-grpcErrorToNativeError.js index f9b5d1a8b..7641af54f 100644 --- a/Framework/Backend/test/errors/mocha-grpcErrorToNativeError.js +++ b/Framework/Backend/test/errors/mocha-grpcErrorToNativeError.js @@ -10,26 +10,28 @@ * In applying this license CERN does not waive the privileges and immunities * granted to it by virtue of its status as an Intergovernmental Organization * or submit itself to any jurisdiction. -*/ + */ -/* eslint-disable max-len */ -const {grpcErrorToNativeError} = require('../../errors/grpcErrorToNativeError.js'); -const {InvalidInputError} = require('../../errors/InvalidInputError.js'); -const {NotFoundError} = require('../../errors/NotFoundError.js'); -const {ServiceUnavailableError} = require('../../errors/ServiceUnavailableError.js'); -const {TimeoutError} = require('../../errors/TimeoutError.js'); -const {UnauthorizedAccessError} = require('../../errors/UnauthorizedAccessError.js'); +const { grpcErrorToNativeError } = require('../../errors/grpcErrorToNativeError.js'); +const { InvalidInputError } = require('../../errors/InvalidInputError.js'); +const { NotFoundError } = require('../../errors/NotFoundError.js'); +const { ServiceUnavailableError } = require('../../errors/ServiceUnavailableError.js'); +const { TimeoutError } = require('../../errors/TimeoutError.js'); +const { UnauthorizedAccessError } = require('../../errors/UnauthorizedAccessError.js'); const assert = require('assert'); -describe(`'grpcErrorToNativeError' test suite`, function() { +describe(`'grpcErrorToNativeError' test suite`, () => { it('should successfully convert gRPC errors to native errors', () => { - assert.deepStrictEqual(grpcErrorToNativeError({code: 3, message: 'invalid'}), new InvalidInputError('invalid')); - assert.deepStrictEqual(grpcErrorToNativeError({code: 4, message: 'timeout'}), new TimeoutError('timeout')); - assert.deepStrictEqual(grpcErrorToNativeError({code: 5, message: 'not-found'}), new NotFoundError('not-found')); - assert.deepStrictEqual(grpcErrorToNativeError({code: 7, message: 'unauthorized'}), new UnauthorizedAccessError('unauthorized')); - assert.deepStrictEqual(grpcErrorToNativeError({code: 14, message: 'service-unavailable'}), new ServiceUnavailableError('service-unavailable')); - assert.deepStrictEqual(grpcErrorToNativeError({code: 100, message: 'standard-error'}), new Error('standard-error')); - assert.deepStrictEqual(grpcErrorToNativeError({message: 'standard-error'}), new Error('standard-error')); - }) + assert.deepStrictEqual(grpcErrorToNativeError({ code: 3, message: 'invalid' }), new InvalidInputError('invalid')); + assert.deepStrictEqual(grpcErrorToNativeError({ code: 4, message: 'timeout' }), new TimeoutError('timeout')); + assert.deepStrictEqual(grpcErrorToNativeError({ code: 5, message: 'not-found' }), new NotFoundError('not-found')); + assert.deepStrictEqual(grpcErrorToNativeError({ code: 7, message: 'unauthorized' }), new UnauthorizedAccessError('unauthorized')); + assert.deepStrictEqual( + grpcErrorToNativeError({ code: 14, message: 'service-unavailable' }), + new ServiceUnavailableError('service-unavailable'), + ); + assert.deepStrictEqual(grpcErrorToNativeError({ code: 100, message: 'standard-error' }), new Error('standard-error')); + assert.deepStrictEqual(grpcErrorToNativeError({ message: 'standard-error' }), new Error('standard-error')); + }); }); diff --git a/Framework/Backend/test/errors/mocha-updateExpressResponseFromNativeError.test.js b/Framework/Backend/test/errors/mocha-updateExpressResponseFromNativeError.test.js index e57491520..58ad383f4 100644 --- a/Framework/Backend/test/errors/mocha-updateExpressResponseFromNativeError.test.js +++ b/Framework/Backend/test/errors/mocha-updateExpressResponseFromNativeError.test.js @@ -10,56 +10,55 @@ * In applying this license CERN does not waive the privileges and immunities * granted to it by virtue of its status as an Intergovernmental Organization * or submit itself to any jurisdiction. -*/ + */ -/* eslint-disable max-len */ -const {InvalidInputError} = require('../../errors/InvalidInputError.js'); -const {NotFoundError} = require('../../errors/NotFoundError.js'); -const {ServiceUnavailableError} = require('../../errors/ServiceUnavailableError.js'); -const {TimeoutError} = require('../../errors/TimeoutError.js'); -const {UnauthorizedAccessError} = require('../../errors/UnauthorizedAccessError.js'); -const {updateAndSendExpressResponseFromNativeError} = require('../../errors/updateAndSendExpressResponseFromNativeError.js'); +const { InvalidInputError } = require('../../errors/InvalidInputError.js'); +const { NotFoundError } = require('../../errors/NotFoundError.js'); +const { ServiceUnavailableError } = require('../../errors/ServiceUnavailableError.js'); +const { TimeoutError } = require('../../errors/TimeoutError.js'); +const { UnauthorizedAccessError } = require('../../errors/UnauthorizedAccessError.js'); +const { updateAndSendExpressResponseFromNativeError } = require('../../errors/updateAndSendExpressResponseFromNativeError.js'); const assert = require('assert'); const sinon = require('sinon'); -describe(`'updateAndSendExpressResponseFromNativeError' test suite`, function() { +describe(`'updateAndSendExpressResponseFromNativeError' test suite`, () => { let response; before(() => { response = { status: sinon.stub().returnsThis(), json: sinon.stub(), - } + }; }); it('should successfully update response based on InvalidInputError', () => { updateAndSendExpressResponseFromNativeError(response, new InvalidInputError('Bad Parameters received')); assert.ok(response.status.calledWith(400)); - assert.ok(response.json.calledWith({status: 400, title: 'Invalid Input', message: 'Bad Parameters received'})); + assert.ok(response.json.calledWith({ status: 400, title: 'Invalid Input', message: 'Bad Parameters received' })); }); it('should successfully update response based on UnauthorizedAccessError', () => { updateAndSendExpressResponseFromNativeError(response, new UnauthorizedAccessError('You shall not pass')); assert.ok(response.status.calledWith(403)); - assert.ok(response.json.calledWith({status: 403, title: 'Unauthorized Access', message: 'You shall not pass'})); + assert.ok(response.json.calledWith({ status: 403, title: 'Unauthorized Access', message: 'You shall not pass' })); }); it('should successfully update response based on NotFoundError', () => { updateAndSendExpressResponseFromNativeError(response, new NotFoundError('Entity could not be found')); assert.ok(response.status.calledWith(404)); - assert.ok(response.json.calledWith({status: 404, title: 'Not Found', message: 'Entity could not be found'})); + assert.ok(response.json.calledWith({ status: 404, title: 'Not Found', message: 'Entity could not be found' })); }); it('should successfully update response based on TimeoutError', () => { updateAndSendExpressResponseFromNativeError(response, new TimeoutError('Ran out of time')); assert.ok(response.status.calledWith(408)); - assert.ok(response.json.calledWith({status: 408, title: 'Timeout', message: 'Ran out of time'})); + assert.ok(response.json.calledWith({ status: 408, title: 'Timeout', message: 'Ran out of time' })); }); it('should successfully update response based on ServiceUnavailableError', () => { updateAndSendExpressResponseFromNativeError(response, new ServiceUnavailableError('Service does not want to cooperate')); assert.ok(response.status.calledWith(503)); - assert.ok(response.json.calledWith({status: 503, title: 'Service Unavailable', message: 'Service does not want to cooperate'})); + assert.ok(response.json.calledWith({ status: 503, title: 'Service Unavailable', message: 'Service does not want to cooperate' })); }); it('should successfully update response based on general Error', () => { updateAndSendExpressResponseFromNativeError(response, new Error('Some Error happened')); assert.ok(response.status.calledWith(500)); - assert.ok(response.json.calledWith({status: 500, title: 'Unknown Error', message: 'Some Error happened'})); + assert.ok(response.json.calledWith({ status: 500, title: 'Unknown Error', message: 'Some Error happened' })); }); }); diff --git a/Framework/Backend/test/log/mocha-infologgermessage.js b/Framework/Backend/test/log/mocha-infologgermessage.js index 47f906275..a628d4303 100644 --- a/Framework/Backend/test/log/mocha-infologgermessage.js +++ b/Framework/Backend/test/log/mocha-infologgermessage.js @@ -10,31 +10,51 @@ * In applying this license CERN does not waive the privileges and immunities * granted to it by virtue of its status as an Intergovernmental Organization * or submit itself to any jurisdiction. -*/ + */ -const {strictEqual, deepStrictEqual} = require('assert'); +const { strictEqual, deepStrictEqual } = require('assert'); const InfoLoggerMessage = require('../../log/InfoLoggerMessage.js'); describe('Logging: InfoLoggerMessage', () => { describe('_removeNewLinesAndTabs: ', () => { it('should successfully parse Error into one line string message', () => { - strictEqual(InfoLoggerMessage._removeNewLinesAndTabs(new Error('Error in Error')), - 'Error: Error in Error', 'Parsed message from Error is incorrect'); + strictEqual( + InfoLoggerMessage._removeNewLinesAndTabs(new Error('Error in Error')), + 'Error: Error in Error', + 'Parsed message from Error is incorrect', + ); }); it('should successfully parse Object into one line string message', () => { - // eslint-disable-next-line require-jsdoc - class T {constructor() {this.message = 'Test Class Parse';} } - strictEqual(InfoLoggerMessage._removeNewLinesAndTabs(new T()), - '{"message":"Test Class Parse"}', 'Parsed message from class T is incorrect'); - strictEqual(InfoLoggerMessage._removeNewLinesAndTabs({error: 'Error in JSON'}), - '{"error":"Error in JSON"}', 'Parsed message from JSON is incorrect'); + /** + * Test class for parsing + */ + class T { + /** + * Constructor for T class + */ + constructor() { + this.message = 'Test Class Parse'; + } + } + strictEqual( + InfoLoggerMessage._removeNewLinesAndTabs(new T()), + '{"message":"Test Class Parse"}', + 'Parsed message from class T is incorrect', + ); + strictEqual( + InfoLoggerMessage._removeNewLinesAndTabs({ error: 'Error in JSON' }), + '{"error":"Error in JSON"}', + 'Parsed message from JSON is incorrect', + ); }); it('should successfully parse multi-line string into one line string message', () => { const multiLineString = 'SomeError\nHappenedHere\nAnd\nthere\tplus\tsomeother'; - strictEqual(InfoLoggerMessage._removeNewLinesAndTabs(multiLineString), - 'SomeError HappenedHere And there plus someother'); + strictEqual( + InfoLoggerMessage._removeNewLinesAndTabs(multiLineString), + 'SomeError HappenedHere And there plus someother', + ); }); it('should successfully return empty string if log is undefined or null', () => { @@ -48,9 +68,7 @@ describe('Logging: InfoLoggerMessage', () => { describe('getComponentsOfMessage: ', () => { it('should successfully return default values for empty log message', () => { const log = new InfoLoggerMessage(); - const expectedComponents = [ - '-oSeverity=Info', '-oLevel=11', '-oSystem=GUI', '-oFacility=gui', '' - ]; + const expectedComponents = ['-oSeverity=Info', '-oLevel=11', '-oSystem=GUI', '-oFacility=gui', '']; deepStrictEqual(log.getComponentsOfMessage(), expectedComponents); }); @@ -59,11 +77,9 @@ describe('Logging: InfoLoggerMessage', () => { severity: 'Error', system: 'tests', run: 12345, - message: 'TestWithJSON' + message: 'TestWithJSON', }); - const expectedComponents = [ - '-oSeverity=Error', '-oLevel=11', '-oSystem=tests', '-oFacility=gui', '-oRun=12345', 'TestWithJSON' - ]; + const expectedComponents = ['-oSeverity=Error', '-oLevel=11', '-oSystem=tests', '-oFacility=gui', '-oRun=12345', 'TestWithJSON']; deepStrictEqual(log.getComponentsOfMessage(), expectedComponents); }); diff --git a/Framework/Backend/test/log/mocha-log.js b/Framework/Backend/test/log/mocha-log.js index 2db7d07e2..5659cc418 100644 --- a/Framework/Backend/test/log/mocha-log.js +++ b/Framework/Backend/test/log/mocha-log.js @@ -12,8 +12,7 @@ * or submit itself to any jurisdiction. */ -/* eslint-disable max-len */ -/* eslint-disable require-jsdoc */ +/* eslint-disable @stylistic/js/max-len */ const assert = require('assert'); const fs = require('fs'); @@ -21,11 +20,11 @@ const fs = require('fs'); const config = require('../config.js'); const InfoLoggerReceiver = require('../../log/InfoLoggerReceiver.js'); -const {LogManager} = require('../../log/LogManager'); -const {Logger} = require('../../log/Logger.js'); -const {InfoLoggerSender} = require('../../index.js'); +const { LogManager } = require('../../log/LogManager'); +const { Logger } = require('../../log/Logger.js'); +const { InfoLoggerSender } = require('../../index.js'); const sinon = require('sinon'); -const {LogLevel} = require('../../log/LogLevel.js'); +const { LogLevel } = require('../../log/LogLevel.js'); const WinstonWrapper = require('../../log/WinstonWrapper.js'); describe('Logging via WinstonWrapper', () => { @@ -56,16 +55,15 @@ describe('Logging: InfoLogger protocol', () => { facility: 'P2', partition: 'PHY', errcode: 123, - message: 'test' + message: 'test', }; const parsed = receiver.parse(message); assert.deepStrictEqual(parsed, expected); }); - it('should successfully parse protocol 1.3', (done) => { const receiver = new InfoLoggerReceiver(); - // eslint-disable-next-line max-len + const message = '*1.3#I##1505140368.399439#o2test#O2#143388#root#DAQ#P2#Alice#PHY#dest##123#8#source.cpp#test\n'; const expected = { severity: 'I', @@ -82,7 +80,7 @@ describe('Logging: InfoLogger protocol', () => { errcode: 123, errline: 8, errsource: 'source.cpp', - message: 'test' + message: 'test', }; receiver.on('message', (parsed) => { assert.deepStrictEqual(parsed, expected); @@ -104,13 +102,11 @@ describe('Logging: InfoLogger protocol', () => { } }); const messages = - /* eslint-disable max-len */ `*1.3#I#6#1531982951.042664#aldaqpc031#ldc-TRD-5#37971#alicedaq#DAQ#pauseAndResetRun#TRD#PHYSICS_1##289724##91#pauseAndResetRun.c#POST_PAR completed *1.3#I#6#1531982951.033947#aldaqpc029#ldc-TRD-3#38035#alicedaq#DAQ#pauseAndResetRun#TRD#PHYSICS_1##289724##91#pauseAndResetRun.c#POST_PAR completed *1.3#I#6#1531982951.482111#aldaqpc134#ldc-TPC-C-15#45919#alicedaq#DAQ#pauseAndResetRun#TPC#PHYSICS_1##289724##91#pauseAndResetRun.c#POST_PAR completed *1.3#I#6#1531982951.169333#aldaqpc119#ldc-TPC-C-0#7780#alicedaq#DAQ#pauseAndResetRun#TPC#PHYSICS_1##289724##91#pauseAndResetRun.c#POST_PAR completed`; receiver.onData(messages); - /* eslint-enable max-len */ }); it('should successfully parse chopped log', (done) => { @@ -132,7 +128,7 @@ describe('Logging: InfoLogger protocol', () => { errcode: 123, errline: 8, errsource: 'source.cpp', - message: 'test' + message: 'test', }; let count = 0; receiver.on('message', (parsed) => { @@ -161,7 +157,7 @@ describe('Logging: InfoLogger protocol', () => { } }); const messages = - /* eslint-disable max-len */ + `*1.3#I#6#1531982951.042664#aldaqpc031#ldc-TRD-5#37971#alicedaq#DAQ#pauseAndResetRun#TRD#PHYSICS_1##289724##91#pauseAndResetRun.c#POST_PAR completed *1.3#I#6#1531982951.033947#aldaqpc029#ldc-TRD-3#38035#alicedaq#DAQ#pauseAndResetRun#TRD#PHYSICS_1##289724##91#pauseAndResetRun.c#POST_PAR completed *1.3#I#6#1531982951.482111#aldaqpc134#ldc-TPC-C-15#45919#alicedaq#DAQ#pauseAndResetRun#TPC#PHYSICS_1##289724##91#pauseAndResetRun.c#POST_PAR completed @@ -169,13 +165,19 @@ describe('Logging: InfoLogger protocol', () => { const messages2 = 'daq#DAQ#pauseAndResetRun#TPC#PHYSICS_1##289724##91#pauseAndResetRun.c#POST_PAR completed\n'; receiver.onData(messages); receiver.onData(messages2); - /* eslint-enable max-len */ }); it('should successfully send to winston only logs with level starting from Developer', () => { const fakeIfologgerSendMessage = sinon.fake(); + /** + * + */ class DummyInfologgerSender extends InfoLoggerSender { + /** + * Method to overwrite for testing purposes + * @param {Log} log - log to be sent + */ sendMessage(log) { fakeIfologgerSendMessage(log); } @@ -187,8 +189,8 @@ describe('Logging: InfoLogger protocol', () => { infologger: new DummyInfologgerSender(winston), }); - logger._sendToInfoLogger('will be sent ', {level: LogLevel.OPERATIONS}); - logger._sendToInfoLogger('will not be sent', {level: LogLevel.DEVELOPER}); + logger._sendToInfoLogger('will be sent ', { level: LogLevel.OPERATIONS }); + logger._sendToInfoLogger('will not be sent', { level: LogLevel.DEVELOPER }); assert.equal(fakeIfologgerSendMessage.calledOnce, true); }); }); diff --git a/Framework/Backend/test/mocha-consul.service.js b/Framework/Backend/test/mocha-consul.service.js index 7c55a5826..f73199af6 100644 --- a/Framework/Backend/test/mocha-consul.service.js +++ b/Framework/Backend/test/mocha-consul.service.js @@ -10,41 +10,40 @@ * In applying this license CERN does not waive the privileges and immunities * granted to it by virtue of its status as an Intergovernmental Organization * or submit itself to any jurisdiction. -*/ + */ -/* eslint-disable max-len */ const ConsulService = require('./../services/consul.service.js'); const config = require('./../config-default.json'); const assert = require('assert'); const nock = require('nock'); -describe('Consul Service test suite', function() { - describe('Check Initialization of ConsulService', function() { - it('should throw error due to no config being passed', function() { +describe('Consul Service test suite', () => { + describe('Check Initialization of ConsulService', () => { + it('should throw error due to no config being passed', () => { assert.throws(() => { new ConsulService(); }, new Error('Configuration field cannot be empty')); }); - it('should throw error due to empty hostname in consul config', function() { + it('should throw error due to empty hostname in consul config', () => { assert.throws(() => { new ConsulService({}); }, new Error('Hostname field cannot be empty')); }); - it('should throw error due to empty port in consul config', function() { + it('should throw error due to empty port in consul config', () => { assert.throws(() => { - new ConsulService({hostname: 'localhost'}); + new ConsulService({ hostname: 'localhost' }); }, new Error('Port field cannot be empty')); }); - it('should successfully create a consul connector', function() { + it('should successfully create a consul connector', () => { const consul = new ConsulService(config.consul); assert.deepStrictEqual(consul.hostname, 'localhost'); assert.deepStrictEqual(consul.port, 8080); }); - it('should successfully set default values for API paths', function() { + it('should successfully set default values for API paths', () => { const consul = new ConsulService(config.consul); assert.deepStrictEqual(consul.servicesPath, '/v1/catalog/services'); assert.deepStrictEqual(consul.kvPath, '/v1/kv/'); @@ -53,20 +52,20 @@ describe('Consul Service test suite', function() { }); }); - describe('Check `getConsulLeaderStatus()`', function() { + describe('Check `getConsulLeaderStatus()`', () => { const consul = new ConsulService(config.consul); it('should successfully check if consul status is healthy', () => { nock('http://localhost:8080') .get('/v1/status/leader') - .reply(200, `"localhost:8080"`); + .reply(200, '"localhost:8080"'); return consul.getConsulLeaderStatus().then((res) => assert.deepStrictEqual(res, 'localhost:8080')); }); it('should reject with error if is unable to parse response from leader', async () => { nock('http://localhost:8080') .get('/v1/status/leader') - .reply(200, `Unable to contact leader`); + .reply(200, 'Unable to contact leader'); return assert.rejects(async () => { await consul.getConsulLeaderStatus(); }, new Error('Unable to parse JSON')); @@ -91,37 +90,37 @@ describe('Consul Service test suite', function() { }); }); - describe('Check various ways of retrieving keys', function() { + describe('Check various ways of retrieving keys', () => { const consul = new ConsulService(config.consul); - it('should successfully build a call to retrieve all keys', function() { + it('should successfully build a call to retrieve all keys', () => { nock('http://localhost:8080') .get('/v1/kv/?keys=true') .reply(200, ['a/b', 'b/c']); return consul.getKeys().then((res) => assert.deepStrictEqual(res, ['a/b', 'b/c'])); }); - it('should successfully build the call to retrieve keys with a predefined keyPrefix', function() { + it('should successfully build the call to retrieve keys with a predefined keyPrefix', () => { nock('http://localhost:8080') .get('/v1/kv/keyprefix/?keys=true') .reply(200, ['keyprefix/somekey']); return consul.getKeysByPrefix('keyprefix').then((res) => assert.deepStrictEqual(res, ['keyprefix/somekey'])); }); - it('should successfully build the call to retrieve keys with a predefined keyPrefix in format `/keyprefix` ', function() { + it('should successfully build the call to retrieve keys with a predefined keyPrefix in format `/keyprefix` ', () => { nock('http://localhost:8080') .get('/v1/kv/keyprefix/?keys=true') .reply(200, ['keyprefix/somekey']); return consul.getKeysByPrefix('/keyprefix').then((res) => assert.deepStrictEqual(res, ['keyprefix/somekey'])); }); - it('should successfully build the call to retrieve keys with a predefined keyPrefix in format `keyprefix/` ', function() { + it('should successfully build the call to retrieve keys with a predefined keyPrefix in format `keyprefix/` ', () => { nock('http://localhost:8080') .get('/v1/kv/keyprefix/?keys=true') .reply(200, ['keyprefix/somekey']); return consul.getKeysByPrefix('keyprefix/').then((res) => assert.deepStrictEqual(res, ['keyprefix/somekey'])); }); - it('should successfully build the call to retrieve keys with a predefined keyPrefix in format `/keyprefix/` ', function() { + it('should successfully build the call to retrieve keys with a predefined keyPrefix in format `/keyprefix/` ', () => { nock('http://localhost:8080') .get('/v1/kv/keyprefix/?keys=true') .reply(200, ['keyprefix/somekey']); @@ -129,52 +128,58 @@ describe('Consul Service test suite', function() { }); }); - describe('Check various ways of retrieving values based on key', function() { + describe('Check various ways of retrieving values based on key', () => { const consul = new ConsulService(config.consul); - it('should successfully build a call to retrieve all keys', function() { + it('should successfully build a call to retrieve all keys', () => { nock('http://localhost:8080') .get('/v1/kv/?keys=true') .reply(200, ['a/b', 'b/c']); return consul.getKeys().then((res) => assert.deepStrictEqual(res, ['a/b', 'b/c'])); }); - it('should successfully build the call to retrieve a value by a key in format `key`', function() { + it('should successfully build the call to retrieve a value by a key in format `key`', () => { nock('http://localhost:8080') .get('/v1/kv/keyprefix/someotherkey') - .reply(200, {key: 'keyprefix/someotherkey'}); - return consul.getValueObjectByKey('keyprefix/someotherkey').then((res) => assert.deepStrictEqual(res, {key: 'keyprefix/someotherkey'})); + .reply(200, { key: 'keyprefix/someotherkey' }); + return consul.getValueObjectByKey('keyprefix/someotherkey').then((res) => assert.deepStrictEqual(res, { key: 'keyprefix/someotherkey' })); }); - it('should successfully build the call to retrieve a value by a key in format `/key/`', function() { + it('should successfully build the call to retrieve a value by a key in format `/key/`', () => { nock('http://localhost:8080') .get('/v1/kv/keyprefix/someotherkey') - .reply(200, {key: 'keyprefix/someotherkey'}); - return consul.getValueObjectByKey('/keyprefix/someotherkey/').then((res) => assert.deepStrictEqual(res, {key: 'keyprefix/someotherkey'})); + .reply(200, { key: 'keyprefix/someotherkey' }); + return consul.getValueObjectByKey('/keyprefix/someotherkey/') + .then((res) => assert.deepStrictEqual(res, { key: 'keyprefix/someotherkey' })); }); - it('should successfully build the call to retrieve a raw value by a key in format `/key/`', function() { + it('should successfully build the call to retrieve a raw value by a key in format `/key/`', () => { nock('http://localhost:8080') .get('/v1/kv/keyprefix/someotherkey?raw=true') - .reply(200, `"value"`); + .reply(200, '"value"'); return consul.getOnlyRawValueByKey('/keyprefix/someotherkey/').then((res) => assert.deepStrictEqual(res, 'value')); }); - it('should successfully build the call to retrieve all values with a keyprefix in format `/key/`', function() { + it('should successfully build the call to retrieve all values with a keyprefix in format `/key/`', () => { nock('http://localhost:8080') .get('/v1/kv/keyprefix?recurse=true') - .reply(200, [{Key: 'keyprefix/some', Value: 'VGVzdFZhbHVl'}, {Key: 'keyprefix/other', Value: 'VGVzdFZhbHVl'}]); - return consul.getValuesByKeyPrefix('/keyprefix/').then((res) => assert.deepStrictEqual(res, [{Key: 'keyprefix/some', Value: 'VGVzdFZhbHVl'}, {Key: 'keyprefix/other', Value: 'VGVzdFZhbHVl'}])); + .reply(200, [{ Key: 'keyprefix/some', Value: 'VGVzdFZhbHVl' }, { Key: 'keyprefix/other', Value: 'VGVzdFZhbHVl' }]); + return consul.getValuesByKeyPrefix('/keyprefix/') + .then((res) => assert.deepStrictEqual(res, [ + { Key: 'keyprefix/some', Value: 'VGVzdFZhbHVl' }, + { Key: 'keyprefix/other', Value: 'VGVzdFZhbHVl' }, + ])); }); - it('should successfully build the call to retrieve all raw values with a keyprefix in format `/key/`', function() { - const objectMeta = {Key: 'keyprefix/some', Value: 'VGVzdFZhbHVl', lastModified: 123456}; - const otherObjectMeta = {Key: 'keyprefix/other', Value: 'ewogbmFtZTogJ3Rlc3QnLAogdmFsdWU6ICd2YWx1ZScsCn0=', lastModified: 123456}; + it('should successfully build the call to retrieve all raw values with a keyprefix in format `/key/`', () => { + const objectMeta = { Key: 'keyprefix/some', Value: 'VGVzdFZhbHVl', lastModified: 123456 }; + const otherObjectMeta = { Key: 'keyprefix/other', Value: 'ewogbmFtZTogJ3Rlc3QnLAogdmFsdWU6ICd2YWx1ZScsCn0=', lastModified: 123456 }; nock('http://localhost:8080') .get('/v1/kv/keyprefix?recurse=true') .reply(200, [objectMeta, otherObjectMeta]); const expectedValue = 'TestValue'; const expectedOtherValue = '{\n name: \'test\',\n value: \'value\',\n}'; - return consul.getOnlyRawValuesByKeyPrefix('/keyprefix/').then((res) => assert.deepStrictEqual(res, {'keyprefix/some': expectedValue, 'keyprefix/other': expectedOtherValue})); + return consul.getOnlyRawValuesByKeyPrefix('/keyprefix/') + .then((res) => assert.deepStrictEqual(res, { 'keyprefix/some': expectedValue, 'keyprefix/other': expectedOtherValue })); }); }); @@ -187,14 +192,14 @@ describe('Consul Service test suite', function() { Tags: [ 'QcTask/example', - 'ITSRAWDS/example' + 'ITSRAWDS/example', ], Meta: {}, Port: 80, Address: '', - Weights: {Passing: 1, Warning: 1}, - EnableTagOverride: false - } + Weights: { Passing: 1, Warning: 1 }, + EnableTagOverride: false, + }, }; const consul = new ConsulService(config.consul); it('should successfully receive a JSON and parse it in a list of services', () => { @@ -208,12 +213,16 @@ describe('Consul Service test suite', function() { describe('Check PUT transaction calls', () => { it('should successfully send to consul a batch of transactions and all should succeed', async () => { const expectedBatches = [ - [...Array.from({length: 64}, (x, i) => ( - {KV: {Verb: 'set', Key: 'key', Value: Buffer.from(`value/${i}`).toString('base64')}} - ))], - [...Array.from({length: 6}, (x, i) => ( - {KV: {Verb: 'set', Key: 'key', Value: Buffer.from(`value/${i + 64}`).toString('base64')}} - ))] + [ + ...Array.from({ length: 64 }, (x, i) => ( + { KV: { Verb: 'set', Key: 'key', Value: Buffer.from(`value/${i}`).toString('base64') } } + )), + ], + [ + ...Array.from({ length: 6 }, (x, i) => ( + { KV: { Verb: 'set', Key: 'key', Value: Buffer.from(`value/${i + 64}`).toString('base64') } } + )), + ], ]; nock('http://localhost:8080') .put('/v1/txn', expectedBatches[0]) @@ -221,20 +230,24 @@ describe('Consul Service test suite', function() { nock('http://localhost:8080') .put('/v1/txn', expectedBatches[1]) .reply(200, {}); - const list = [...Array.from({length: 70}, (x, i) => ({key: `value/${i}`}))]; + const list = [...Array.from({ length: 70 }, (x, i) => ({ key: `value/${i}` }))]; const consul = new ConsulService(config.consul); const response = await consul.putListOfKeyValues(list); - assert.deepStrictEqual(response, {allPut: true}); + assert.deepStrictEqual(response, { allPut: true }); }); it('should successfully send to consul a batch of transactions and not all should succeed', async () => { const expectedBatches = [ - [...Array.from({length: 64}, (x, i) => ( - {KV: {Verb: 'set', Key: 'key', Value: Buffer.from(`value/${i}`).toString('base64')}} - ))], - [...Array.from({length: 6}, (x, i) => ( - {KV: {Verb: 'set', Key: 'key', Value: Buffer.from(`value/${i + 64}`).toString('base64')}} - ))] + [ + ...Array.from({ length: 64 }, (x, i) => ( + { KV: { Verb: 'set', Key: 'key', Value: Buffer.from(`value/${i}`).toString('base64') } } + )), + ], + [ + ...Array.from({ length: 6 }, (x, i) => ( + { KV: { Verb: 'set', Key: 'key', Value: Buffer.from(`value/${i + 64}`).toString('base64') } } + )), + ], ]; nock('http://localhost:8080') .put('/v1/txn', expectedBatches[0]) @@ -242,10 +255,10 @@ describe('Consul Service test suite', function() { nock('http://localhost:8080') .put('/v1/txn', expectedBatches[1]) .replyWithError('Service unavailable'); - const list = [...Array.from({length: 70}, (x, i) => ({key: `value/${i}`}))]; + const list = [...Array.from({ length: 70 }, (x, i) => ({ key: `value/${i}` }))]; const consul = new ConsulService(config.consul); const response = await consul.putListOfKeyValues(list); - assert.deepStrictEqual(response, {allPut: false}); + assert.deepStrictEqual(response, { allPut: false }); }); afterEach(nock.cleanAll); }); @@ -267,13 +280,13 @@ describe('Consul Service test suite', function() { port: config.consul.port, path: path, method: 'PUT', - headers: {'Content-Type': 'application/json', 'Content-Length': data.length} + headers: { 'Content-Type': 'application/json', 'Content-Length': data.length }, }; assert.deepStrictEqual(options, expectedOptions); }); it('should successfully build request options for PUT call when data is not string', () => { - const data = {key: 'some-value'}; + const data = { key: 'some-value' }; const path = 'some-path'; const options = consul._getRequestOptionsPUT(path, data); const expectedOptions = { @@ -281,20 +294,24 @@ describe('Consul Service test suite', function() { port: config.consul.port, path: path, method: 'PUT', - headers: {'Content-Type': 'application/json', 'Content-Length': JSON.stringify(data).length} + headers: { 'Content-Type': 'application/json', 'Content-Length': JSON.stringify(data).length }, }; assert.deepStrictEqual(options, expectedOptions); }); it('should successfully build batches of max 64 with Consul Transaction Objects given a list of KV pairs', () => { - const list = [...Array.from({length: 70}, (x, i) => ({key: `value/${i}`}))]; + const list = [...Array.from({ length: 70 }, (x, i) => ({ key: `value/${i}` }))]; const expectedBatches = [ - [...Array.from({length: 64}, (x, i) => ( - {KV: {Verb: 'set', Key: 'key', Value: Buffer.from(`value/${i}`).toString('base64')}} - ))], - [...Array.from({length: 6}, (x, i) => ( - {KV: {Verb: 'set', Key: 'key', Value: Buffer.from(`value/${i + 64}`).toString('base64')}} - ))] + [ + ...Array.from({ length: 64 }, (x, i) => ( + { KV: { Verb: 'set', Key: 'key', Value: Buffer.from(`value/${i}`).toString('base64') } } + )), + ], + [ + ...Array.from({ length: 6 }, (x, i) => ( + { KV: { Verb: 'set', Key: 'key', Value: Buffer.from(`value/${i + 64}`).toString('base64') } } + )), + ], ]; const batches = consul._mapToConsulKVObjectsLists(list); diff --git a/Framework/Backend/test/mocha-http.js b/Framework/Backend/test/mocha-http.js index 49145fb0e..c5e390623 100644 --- a/Framework/Backend/test/mocha-http.js +++ b/Framework/Backend/test/mocha-http.js @@ -22,7 +22,7 @@ const config = require('./../config-default.json'); const O2TokenService = require('./../services/O2TokenService.js'); const HttpServer = require('./../http/server'); -// as CERN certificates are not signed by any CA +// As CERN certificates are not signed by any CA process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; let httpServer; @@ -31,29 +31,30 @@ const USER = { personid: 0, username: 'test', name: 'Test', - access: 'admin' + access: 'admin', }; const token = tokenService.generateToken(0, 'test', 'Test', 'admin'); describe('REST API', () => { before(() => { httpServer = new HttpServer(config.http, config.jwt); - httpServer.get('/get-insecure', (req, res) => res.json({ok: 1}), {public: true}); - httpServer.get('/get-authenticated-insecure', (req, res) => res.json({session: req.session}), {public: true}); - httpServer.get('/get-request', (req, res) => res.json({ok: 1})); + httpServer.get('/get-insecure', (req, res) => res.json({ ok: 1 }), { public: true }); + httpServer.get('/get-authenticated-insecure', (req, res) => res.json({ session: req.session }), { public: true }); + httpServer.get('/get-request', (req, res) => res.json({ ok: 1 })); httpServer.get('/get-error', (req, res, next) => next(new Error('Some unexpected error'))); httpServer.get('/get-crash', () => { throw new Error('Some unexpected error'); }); - httpServer.post('/post-request', (req, res) => res.json({ok: 1})); - httpServer.post('/post-with-body', (req, res) => res.json({body: req.body})); - httpServer.put('/put-request', (req, res) => res.json({ok: 1})); - httpServer.patch('/patch-request', (req, res) => res.json({ok: 1})); - httpServer.delete('/delete-request', (req, res) => res.json({ok: 1})); - - httpServer.get('/get-middleware', + httpServer.post('/post-request', (req, res) => res.json({ ok: 1 })); + httpServer.post('/post-with-body', (req, res) => res.json({ body: req.body })); + httpServer.put('/put-request', (req, res) => res.json({ ok: 1 })); + httpServer.patch('/patch-request', (req, res) => res.json({ ok: 1 })); + httpServer.delete('/delete-request', (req, res) => res.json({ ok: 1 })); + + httpServer.get( + '/get-middleware', (req, res, next) => isNaN(req.query.id) ? next(new Error('Not Allowed')) : next(), - (req, res) => res.json({ok: 1}) + (req, res) => res.json({ ok: 1 }), ); }); @@ -89,45 +90,45 @@ describe('REST API', () => { .get('/api/get-insecure') .expect('Content-Type', /json/) .expect(200) - .expect({ok: 1}, done); + .expect({ ok: 1 }, done); }); it('Crashing route should respond 500/JSON', (done) => { request(httpServer) - .get('/api/get-crash?token=' + token) + .get(`/api/get-crash?token=${token}`) .expect('Content-Type', /json/) .expect(500) .expect({ error: '500 - Server error', - message: 'Something went wrong, please try again or contact an administrator.' + message: 'Something went wrong, please try again or contact an administrator.', }, done); }); it('Error route should respond 500/JSON', (done) => { request(httpServer) - .get('/api/get-error?token=' + token) + .get(`/api/get-error?token=${token}`) .expect('Content-Type', /json/) .expect(500) .expect({ error: '500 - Server error', - message: 'Something went wrong, please try again or contact an administrator.' + message: 'Something went wrong, please try again or contact an administrator.', }, done); }); it('GET with token should respond 200/JSON', (done) => { request(httpServer) - .get('/api/get-request?token=' + token) + .get(`/api/get-request?token=${token}`) .expect('Content-Type', /json/) .expect(200) - .expect({ok: 1}, done); + .expect({ ok: 1 }, done); }); it('GET public with a token should authenticate user', (done) => { request(httpServer) - .get('/api/get-authenticated-insecure?token=' + token) + .get(`/api/get-authenticated-insecure?token=${token}`) .expect('Content-Type', /json/) .expect(200) - .expect({session: USER}, done); + .expect({ session: USER }, done); }); it('GET with an incorrect token should respond 403', (done) => { @@ -152,22 +153,22 @@ describe('REST API', () => { it('GET with an incorrect path should respond 404', (done) => { request(httpServer) - .get('/api/get-wrong?token=' + token) + .get(`/api/get-wrong?token=${token}`) .expect(404, done); }); describe('Middleware handler', () => { it('should return ok if the middleware satisfied the query condition', (done) => { request(httpServer) - .get('/api/get-middleware?id=1&token=' + token) + .get(`/api/get-middleware?id=1&token=${token}`) .expect('Content-Type', /json/) .expect(200) - .expect({ok: 1}, done); + .expect({ ok: 1 }, done); }); it('should return error 500 if the middleware dissatisfied the query condition', (done) => { request(httpServer) - .get('/api/get-middleware?id=false&token=' + token) + .get(`/api/get-middleware?id=false&token=${token}`) .expect('Content-Type', /json/) .expect(500, done); }); @@ -176,29 +177,29 @@ describe('REST API', () => { describe('404 handler', () => { it('GET with an incorrect path should respond 404, response should be JSON for API', (done) => { request(httpServer) - .get('/api/get-wrong?token=' + token) + .get(`/api/get-wrong?token=${token}`) .expect('Content-Type', /json/) .expect(404, done); }); it('GET with an incorrect path should respond 404, response should be HTML for UI', (done) => { request(httpServer) - .get('/get-wrong?token=' + token) + .get(`/get-wrong?token=${token}`) .expect('Content-Type', /html/) .expect(404, done); }); it('should successfully remove the token from the URL', () => { const req = { - query: {token: 'fdsaf234fsdfa.fsd'}, - originalUrl: '/api/some?query=something&token=fdsaf234fsdfa.fsd' + query: { token: 'fdsaf234fsdfa.fsd' }, + originalUrl: '/api/some?query=something&token=fdsaf234fsdfa.fsd', }; assert.strictEqual(httpServer._parseOriginalUrl(req), '/api/some?query=something&'); }); it('should successfully return the original URL if replacing throwed an error', () => { const req = { - originalUrl: '/api/some?query=something&token=fdsaf234fsdfa.fsd' + originalUrl: '/api/some?query=something&token=fdsaf234fsdfa.fsd', }; assert.strictEqual(httpServer._parseOriginalUrl(req), '/api/some?query=something&token=fdsaf234fsdfa.fsd'); }); @@ -206,22 +207,22 @@ describe('REST API', () => { it('POST with a token should respond 200/JSON', (done) => { request(httpServer) - .post('/api/post-request?token=' + token) + .post(`/api/post-request?token=${token}`) .expect('Content-Type', /json/) .expect(200) - .expect({ok: 1}, done); + .expect({ ok: 1 }, done); }); it('POST with a JSON body', (done) => { - const postData = {fake: 'message'}; + const postData = { fake: 'message' }; request(httpServer) - .post('/api/post-with-body?token=' + token) + .post(`/api/post-with-body?token=${token}`) .send(postData) .set('Accept', 'application/json') .expect('Content-Type', /json/) .expect(200) - .expect({body: postData}, done); + .expect({ body: postData }, done); }); it('POST with an incorrect token should respond 403', (done) => { @@ -233,26 +234,26 @@ describe('REST API', () => { it('PUT with a token should respond 200/JSON', (done) => { request(httpServer) - .put('/api/put-request?token=' + token) + .put(`/api/put-request?token=${token}`) .expect('Content-Type', /json/) .expect(200) - .expect({ok: 1}, done); + .expect({ ok: 1 }, done); }); it('PATCH with a token should respond 200/JSON', (done) => { request(httpServer) - .patch('/api/patch-request?token=' + token) + .patch(`/api/patch-request?token=${token}`) .expect('Content-Type', /json/) .expect(200) - .expect({ok: 1}, done); + .expect({ ok: 1 }, done); }); it('DELETE with a token should respond 200/JSON', (done) => { request(httpServer) - .delete('/api/delete-request?token=' + token) + .delete(`/api/delete-request?token=${token}`) .expect('Content-Type', /json/) .expect(200) - .expect({ok: 1}, done); + .expect({ ok: 1 }, done); }); }); @@ -271,7 +272,7 @@ describe('HTTP server', () => { it('Add custom static path that does not exist', (done) => { try { httpServer.addStaticPath(path.join(__dirname, 'does-not-exist'), 'does-not-exist'); - } catch (error) { + } catch { done(); } }); @@ -284,12 +285,12 @@ describe('HTTP constructor checks', () => { }); it('should succesfully add default limit for request body size to 100kb', async () => { httpServer = new HttpServer(config.http, config.jwt); - assert.strictEqual(httpServer.limit, '100kb', 'Default limit was not set') + assert.strictEqual(httpServer.limit, '100kb', 'Default limit was not set'); }); it('should succesfully add provided limit from configuration for request body size', async () => { const conf = config.http; conf.limit = '10Mb'; httpServer = new HttpServer(conf, config.jwt); - assert.strictEqual(httpServer.limit, '10Mb', 'Provided limit was not set') + assert.strictEqual(httpServer.limit, '10Mb', 'Provided limit was not set'); }); }); diff --git a/Framework/Backend/test/mocha-jira.js b/Framework/Backend/test/mocha-jira.js index 781843506..acfd36097 100644 --- a/Framework/Backend/test/mocha-jira.js +++ b/Framework/Backend/test/mocha-jira.js @@ -10,61 +10,59 @@ * In applying this license CERN does not waive the privileges and immunities * granted to it by virtue of its status as an Intergovernmental Organization * or submit itself to any jurisdiction. -*/ - -/* eslint-disable max-len */ + */ const Jira = require('./../services/jira.js'); const assert = require('assert'); const nock = require('nock'); -describe('JIRA service test suite', function() { +describe('JIRA service test suite', () => { before(nock.activate); - describe('Check Initialization of JIRA Service', function() { - it('should throw error due to no config being passed', function() { + describe('Check Initialization of JIRA Service', () => { + it('should throw error due to no config being passed', () => { assert.throws(() => { new Jira(); }, new Error('Configuration object cannot be empty')); }); - it('should throw error due to empty JIRA URL', function() { + it('should throw error due to empty JIRA URL', () => { assert.throws(() => { new Jira({}); }, new Error('URL must be defined')); }); - it('should throw error due to empty service account', function() { + it('should throw error due to empty service account', () => { assert.throws(() => { - new Jira({url: 'https://localhost', serviceAccount: {}}); + new Jira({ url: 'https://localhost', serviceAccount: {} }); }, new Error('Service account must be defined')); }); - it('should throw error due to missing password of service account', function() { + it('should throw error due to missing password of service account', () => { assert.throws(() => { - new Jira({url: 'https://localhost', serviceAccount: {user: 'test'}}); + new Jira({ url: 'https://localhost', serviceAccount: { user: 'test' } }); }, new Error('Service account must be defined')); }); - it('should throw error due to missing project ID', function() { + it('should throw error due to missing project ID', () => { assert.throws(() => { - new Jira({url: 'https://localhost', serviceAccount: {user: 'test', pass: 'test'}}); + new Jira({ url: 'https://localhost', serviceAccount: { user: 'test', pass: 'test' } }); }, new Error('Project ID must be defined')); }); - it('should successfully create a JIRA service', function() { - const jira = new Jira({url: 'https://localhost:8443', serviceAccount: {user: 'test', pass: 'test'}, projectId: 1}); + it('should successfully create a JIRA service', () => { + const jira = new Jira({ url: 'https://localhost:8443', serviceAccount: { user: 'test', pass: 'test' }, projectId: 1 }); assert.strictEqual(jira.url, 'https://localhost:8443'); assert.deepStrictEqual(jira.projectId, 1); }); }); - describe('Check creating bug issue', function() { - const jira = new Jira({url: 'https://localhost:8443/jira/rest/api/2/issue', serviceAccount: {user: 'test', pass: 'test'}, projectId: 1}); + describe('Check creating bug issue', () => { + const jira = new Jira({ url: 'https://localhost:8443/jira/rest/api/2/issue', serviceAccount: { user: 'test', pass: 'test' }, projectId: 1 }); it('should successfully create a ticket', () => { nock('https://localhost:8443') .post('/jira/rest/api/2/issue') - .basicAuth({user: 'test', pass: 'test'}) + .basicAuth({ user: 'test', pass: 'test' }) .reply(200, '{"key":"OPRO-123", "self":"https://localhost:8443/jira/OPRO-123", "id":1234}'); return jira.createBugIssue('alice', 'bob', 'Run fails').then((res) => { assert.deepStrictEqual(res.key, 'OPRO-123'); diff --git a/Framework/Backend/test/mocha-message.js b/Framework/Backend/test/mocha-message.js index e25dd461f..221e8ee46 100644 --- a/Framework/Backend/test/mocha-message.js +++ b/Framework/Backend/test/mocha-message.js @@ -10,7 +10,7 @@ * In applying this license CERN does not waive the privileges and immunities * granted to it by virtue of its status as an Intergovernmental Organization * or submit itself to any jurisdiction. -*/ + */ const assert = require('assert'); const WebSocketMessage = require('./../websocket/message.js'); @@ -19,9 +19,9 @@ describe('WebSocket message', () => { it('Create and verify message instance', () => { const command = 'test-cmd'; const code = 200; - const payload = {message: 'test message'}; + const payload = { message: 'test message' }; const response = new WebSocketMessage(code).setCommand(command).setPayload(payload); - const json = response.json; + const { json } = response; assert.equal(json.command, command); assert.equal(json.code, code); @@ -31,8 +31,8 @@ describe('WebSocket message', () => { it('Parse message', () => { const message = { command: 'test', - payload: {test: 'value'}, - token: 'token' + payload: { test: 'value' }, + token: 'token', }; new WebSocketMessage().parse(JSON.stringify(message)) .then((res) => { @@ -47,7 +47,7 @@ describe('WebSocket message', () => { it('Parse invalid message without token', (done) => { const message = { command: 'test', - test: 'value' + test: 'value', }; new WebSocketMessage().parse(JSON.stringify(message)) .then(() => { diff --git a/Framework/Backend/test/mocha-mysql.js b/Framework/Backend/test/mocha-mysql.js index c47143447..49c54e89e 100644 --- a/Framework/Backend/test/mocha-mysql.js +++ b/Framework/Backend/test/mocha-mysql.js @@ -10,12 +10,12 @@ * In applying this license CERN does not waive the privileges and immunities * granted to it by virtue of its status as an Intergovernmental Organization * or submit itself to any jurisdiction. -*/ + */ const MySQL = require('../db/mysql.js'); const sinon = require('sinon'); const assert = require('assert'); -const AssertionError = require('assert').AssertionError; +const { AssertionError } = require('assert'); let db = null; @@ -27,25 +27,25 @@ describe('MySQL Data Connector', () => { it('should throw error due to missing configuration', () => { assert.throws(() => { new MySQL(); - }, new AssertionError({message: 'Missing config', expected: true, operator: '=='})); + }, new AssertionError({ message: 'Missing config', expected: true, operator: '==' })); }); it('should throw error due to missing configuration parameter: host', () => { assert.throws(() => { new MySQL({}); - }, new AssertionError({message: 'Missing config value: mysql.host', expected: true, operator: '=='})); + }, new AssertionError({ message: 'Missing config value: mysql.host', expected: true, operator: '==' })); }); it('should throw error due to missing configuration parameter: user', () => { assert.throws(() => { - new MySQL({host: 'test'}); - }, new AssertionError({message: 'Missing config value: mysql.user', expected: true, operator: '=='})); + new MySQL({ host: 'test' }); + }, new AssertionError({ message: 'Missing config value: mysql.user', expected: true, operator: '==' })); }); it('should throw error due to missing configuration parameter: database', () => { assert.throws(() => { - new MySQL({host: 'test', user: 'test'}); - }, new AssertionError({message: 'Missing config value: mysql.database', expected: true, operator: '=='})); + new MySQL({ host: 'test', user: 'test' }); + }, new AssertionError({ message: 'Missing config value: mysql.database', expected: true, operator: '==' })); }); it('should successfully initialize mysql connector with all parameters', () => { @@ -55,7 +55,7 @@ describe('MySQL Data Connector', () => { database: 'db', port: 8080, password: 'admin', - timeout: 2020 + timeout: 2020, }; db = new MySQL(config); }); @@ -75,13 +75,13 @@ describe('MySQL Data Connector', () => { const config = { host: 'localhost', user: 'test', - database: 'db' + database: 'db', }; db = new MySQL(config); }); it('should successfully test connection to the pool created', () => { - const connection = {release: sinon.fake.returns(true)}; + const connection = { release: sinon.fake.returns(true) }; const callback = sinon.fake.yields(null, connection); sinon.replace(db.pool, 'getConnection', callback); @@ -144,13 +144,13 @@ describe('MySQL Data Connector', () => { const config = { host: 'localhost', user: 'test', - database: 'db' + database: 'db', }; db = new MySQL(config); }); it('should successfully query', () => { - const connection = {release: sinon.fake.returns(true)}; + const connection = { release: sinon.fake.returns(true) }; const callback = sinon.fake.yields(null, connection); sinon.replace(db.pool, 'query', ({}, callback)); diff --git a/Framework/Backend/test/mocha-notification.js b/Framework/Backend/test/mocha-notification.js index 0f08f4910..e15863ac5 100644 --- a/Framework/Backend/test/mocha-notification.js +++ b/Framework/Backend/test/mocha-notification.js @@ -10,7 +10,7 @@ * In applying this license CERN does not waive the privileges and immunities * granted to it by virtue of its status as an Intergovernmental Organization * or submit itself to any jurisdiction. -*/ + */ const NotificationService = require('./../services/notification.js'); const config = require('./../config-default.json'); @@ -53,8 +53,8 @@ describe('Kafka Connector test suite', () => { /// Remove .skip to actually run tests describe.skip('Check integration with Kafka', () => { - let WebSocket, HttpServer, JwtToken, wsClient; - let wsServer, http, notification, jwt, token + let WebSocket; let HttpServer; let JwtToken; let wsClient; + let wsServer; let http; let notification; let jwt; let token; before(() => { process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; @@ -76,7 +76,7 @@ describe('Kafka Connector test suite', () => { }); it('should send and receive a notification', async () => { - const client = new wsClient('ws://localhost:' + config.http.port + '/?token=' + token); + const client = new wsClient(`ws://localhost:${config.http.port}/?token=${token}`); client.on('message', (message) => { const parsed = JSON.parse(message); if (parsed.command == 'authed') { diff --git a/Framework/Backend/test/mocha-o2web-token.js b/Framework/Backend/test/mocha-o2web-token.js index 34c393c64..ae6d35b96 100644 --- a/Framework/Backend/test/mocha-o2web-token.js +++ b/Framework/Backend/test/mocha-o2web-token.js @@ -10,15 +10,14 @@ * In applying this license CERN does not waive the privileges and immunities * granted to it by virtue of its status as an Intergovernmental Organization * or submit itself to any jurisdiction. -*/ + */ -const {jwt} = require('../config-default.json'); +const { jwt } = require('../config-default.json'); const O2TokenService = require('./../services/O2TokenService.js'); -const {JsonWebTokenError} = require('jsonwebtoken'); +const { JsonWebTokenError } = require('jsonwebtoken'); const assert = require('assert'); describe('JSON Web Token', () => { - describe('O2TokenService Initialization', () => { it('should successfully initialize constructor with provided configuration', () => { const o2Token = new O2TokenService(jwt); @@ -32,8 +31,8 @@ describe('JSON Web Token', () => { const jwtConfig = { maxAge: '2m', issuer: 'alice-o2-gui', - secret: null - } + secret: null, + }; const o2Token = new O2TokenService(jwtConfig); assert.strictEqual(o2Token._expiration, '1d'); assert.strictEqual(o2Token._maxAge, jwtConfig.maxAge); @@ -46,7 +45,7 @@ describe('JSON Web Token', () => { it('should successfully generate token based on provided configuration', () => { const o2Token = new O2TokenService(jwt); const token = o2Token.generateToken(100, 'bob', 'John Bob', 'admin'); - const {id, username, name, access} = o2Token.verify(token); + const { id, username, name, access } = o2Token.verify(token); assert.strictEqual(id, 100); assert.strictEqual(username, 'bob'); assert.strictEqual(name, 'John Bob'); @@ -56,7 +55,7 @@ describe('JSON Web Token', () => { it('should successfully generate token based on provided configuration and default parameters', () => { const o2Token = new O2TokenService(jwt); const token = o2Token.generateToken(101, 'alice', 'Alice O2'); - const {id, username, name, access} = o2Token.verify(token); + const { id, username, name, access } = o2Token.verify(token); assert.strictEqual(id, 101); assert.strictEqual(username, 'alice'); assert.strictEqual(name, 'Alice O2'); @@ -70,7 +69,7 @@ describe('JSON Web Token', () => { const token = o2Token.generateToken(100, 'bob', 'John Bob', 'admin'); assert.doesNotThrow(() => o2Token.verify(token)); - const {id, username, name, access} = o2Token.verify(token); + const { id, username, name, access } = o2Token.verify(token); assert.strictEqual(id, 100); assert.strictEqual(username, 'bob'); assert.strictEqual(name, 'John Bob'); diff --git a/Framework/Backend/test/mocha-openid.js b/Framework/Backend/test/mocha-openid.js index c525334ae..5ed783677 100644 --- a/Framework/Backend/test/mocha-openid.js +++ b/Framework/Backend/test/mocha-openid.js @@ -10,7 +10,7 @@ * In applying this license CERN does not waive the privileges and immunities * granted to it by virtue of its status as an Intergovernmental Organization * or submit itself to any jurisdiction. -*/ + */ const config = require('./../config-default.json'); const OpenId = require('./../http/openid.js'); diff --git a/Framework/Backend/test/mocha-ws.js b/Framework/Backend/test/mocha-ws.js index 3581aad66..88574db9b 100644 --- a/Framework/Backend/test/mocha-ws.js +++ b/Framework/Backend/test/mocha-ws.js @@ -10,7 +10,7 @@ * In applying this license CERN does not waive the privileges and immunities * granted to it by virtue of its status as an Intergovernmental Organization * or submit itself to any jurisdiction. -*/ + */ const config = require('./../config-default.json'); const WebSocketClient = require('ws'); @@ -22,7 +22,6 @@ const WebSocketMessage = require('./../websocket/message.js'); process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; - let http, ws, tokenService, token; // eslint-disable-line describe('websocket', () => { @@ -37,9 +36,7 @@ describe('websocket', () => { return res; }); - ws.bind('fail', () => { - return {test: 'test'}; - }); + ws.bind('fail', () => ({ test: 'test' })); ws.bind('broadcast', (message) => { const res = new WebSocketMessage().setCommand(message.getCommand()).setBroadcast(); @@ -48,9 +45,7 @@ describe('websocket', () => { }); it('Drop connection due to invalid JWT token', (done) => { - const connection = new WebSocketClient( - 'ws://localhost:' + config.http.port - ); + const connection = new WebSocketClient(`ws://localhost:${config.http.port}`); connection.on('close', () => { connection.terminate(); done(); @@ -58,12 +53,10 @@ describe('websocket', () => { }); it('Connect send, and receive a message', (done) => { - const connection = new WebSocketClient( - 'ws://localhost:' + config.http.port + '/?token=' + token - ); + const connection = new WebSocketClient(`ws://localhost:${config.http.port}/?token=${token}`); connection.on('open', () => { - const message = {command: 'test', token: token}; + const message = { command: 'test', token: token }; connection.send(JSON.stringify(message)); }); connection.on('message', (message) => { @@ -78,12 +71,10 @@ describe('websocket', () => { }); it('Reject message with misformatted fields', (done) => { - const connection = new WebSocketClient( - 'ws://localhost:' + config.http.port + '/?token=' + token - ); + const connection = new WebSocketClient(`ws://localhost:${config.http.port}/?token=${token}`); connection.on('open', () => { - const message = {command: '', token: token}; + const message = { command: '', token: token }; connection.send(JSON.stringify(message)); }); connection.on('message', (message) => { @@ -98,12 +89,10 @@ describe('websocket', () => { }); it('Reject message with 500', (done) => { - const connection = new WebSocketClient( - 'ws://localhost:' + config.http.port + '/?token=' + token - ); + const connection = new WebSocketClient(`ws://localhost:${config.http.port}/?token=${token}`); connection.on('open', () => { - const message = {command: 'fail', token: token}; + const message = { command: 'fail', token: token }; connection.send(JSON.stringify(message)); }); connection.on('message', (message) => { @@ -118,15 +107,14 @@ describe('websocket', () => { }); it('Accept filter with 200', (done) => { - const connection = new WebSocketClient( - 'ws://localhost:' + config.http.port + '/?token=' + token - ); + const connection = new WebSocketClient(`ws://localhost:${config.http.port}/?token=${token}`); connection.on('open', () => { - const message = {command: 'filter', token: token, - filter: (function() { + const message = { command: 'filter', + token: token, + filter: function () { return false; - }).toString()}; + }.toString() }; connection.send(JSON.stringify(message)); }); @@ -143,12 +131,10 @@ describe('websocket', () => { }); it('Request message broadcast with 200', (done) => { - const connection = new WebSocketClient( - 'ws://localhost:' + config.http.port + '/?token=' + token - ); + const connection = new WebSocketClient(`ws://localhost:${config.http.port}/?token=${token}`); connection.on('open', () => { - const message = {command: 'broadcast', token: token}; + const message = { command: 'broadcast', token: token }; connection.send(JSON.stringify(message)); }); diff --git a/Framework/Backend/websocket/message.js b/Framework/Backend/websocket/message.js index 76f9d69ce..53beeeb3d 100644 --- a/Framework/Backend/websocket/message.js +++ b/Framework/Backend/websocket/message.js @@ -10,7 +10,7 @@ * In applying this license CERN does not waive the privileges and immunities * granted to it by virtue of its status as an Intergovernmental Organization * or submit itself to any jurisdiction. -*/ + */ /** * WebSocket module that allows to create response to user request. @@ -33,18 +33,18 @@ class WebSocketMessage { /** * Parses JSON-encoded websocket string into WebSocketMessage object - * @param {string} json + * @param {string} json - JSON-encoded message * @return {object} promise to parsed message */ parse(json) { return new Promise((resolve, reject) => { const parsed = JSON.parse(json); - if ((typeof parsed.command !== 'string') - || (typeof parsed.token !== 'string') - || (parsed.command == '')) { + if (typeof parsed.command !== 'string' + || typeof parsed.token !== 'string' + || parsed.command == '') { this._code = 400; this._command = 'error'; - // eslint-disable-next-line prefer-promise-reject-errors + reject(this); return; } @@ -56,13 +56,16 @@ class WebSocketMessage { } /** - * @return {number} code + * Getter to return the code of the message + * @deprecated + * @return {number} - code */ getCode() { return this._code; } /** + * Getter to return the code of the message * @return {number} code */ get code() { @@ -70,6 +73,7 @@ class WebSocketMessage { } /** + * Getter to retrieve token * @return {string} JWT token */ getToken() { @@ -95,16 +99,20 @@ class WebSocketMessage { } /** - * @param {string} name property name + * Getter to retrieve property by name + * @param {string} name - property name * @return {string} Object property */ getProperty(name) { - if (this._payload.hasOwnProperty(name)) { + if (Object.prototype.hasOwnProperty.call(this._payload, name)) { return this._payload[name]; } + return; } /** + * Getter to retrieve command + * @deprecated * @return {string} command */ getCommand() { @@ -112,6 +120,7 @@ class WebSocketMessage { } /** + * Getter to retrieve command * @return {string} command */ get command() { @@ -128,6 +137,7 @@ class WebSocketMessage { } /** + * Getter to retrieve broadcast flag * @return {bool} broadcast flag */ getBroadcast() { @@ -136,8 +146,9 @@ class WebSocketMessage { /** * Payload setter. - * @param {object} payload + * @param {object} payload - to be sent to user * @return {object} 'this' to allow function call chaining + * @deprecated */ setPayload(payload) { this._payload = payload; @@ -146,33 +157,36 @@ class WebSocketMessage { /** * Payload setter. - * @param {object} payload + * @param {object} payload - to be sent to user */ set payload(payload) { this._payload = payload; } /** - * @return {object} payload - */ + * Getter to retrieve payload + * @return {object} payload + * @deprecated + */ getPayload() { return this._payload; } /** - * @return {object} payload - */ + * Getter to retrieve payload of message + * @return {object} payload + */ get payload() { return this._payload; } /** - * Formats the reponse to object that is ready to be formatted into JSON. + * Formats the response to object that is ready to be formatted into JSON. * @return {object} response */ get json() { const jsonResponse = { - code: this._code + code: this._code, }; if (this._message != '') { jsonResponse.message = this._message; @@ -186,4 +200,5 @@ class WebSocketMessage { return jsonResponse; } } + module.exports = WebSocketMessage; diff --git a/Framework/Backend/websocket/server.js b/Framework/Backend/websocket/server.js index 6dba59478..3d5ef3804 100644 --- a/Framework/Backend/websocket/server.js +++ b/Framework/Backend/websocket/server.js @@ -15,7 +15,7 @@ const WebSocketServer = require('ws').Server; const url = require('url'); const WebSocketMessage = require('./message.js'); -const {LogManager} = require('../log/LogManager'); +const { LogManager } = require('../log/LogManager'); /** * It represents WebSocket server (RFC 6455). @@ -30,16 +30,14 @@ class WebSocket { */ constructor(httpsServer) { this.http = httpsServer; - this.server = new WebSocketServer({server: httpsServer.getServer, clientTracking: true}); + this.server = new WebSocketServer({ server: httpsServer.getServer, clientTracking: true }); this.server.on('connection', (client, request) => this.onconnection(client, request)); this.logger = LogManager.getLogger(`${process.env.npm_config_log_label ?? 'framework'}/ws`); this.logger.info('Server started'); this.callbackArray = []; - this.bind('filter', (message) => { - return new WebSocketMessage(200).setCommand(message.getCommand()); - }); + this.bind('filter', (message) => new WebSocketMessage(200).setCommand(message.getCommand())); this.ping(); } @@ -59,7 +57,7 @@ class WebSocket { * it can send a response back to client by returning WebSocketMessage instance */ bind(name, callback) { - if (this.callbackArray.hasOwnProperty(name)) { + if (Object.prototype.hasOwnProperty.call(this.callbackArray, name)) { throw Error('Callback already exists.'); } this.callbackArray[name] = callback; @@ -67,7 +65,7 @@ class WebSocket { /** * Handles incoming text messages: verifies token and processes request/command. - * @param {object} req + * @param {object} req - HTTP Req object * @return {object} message to be send back to the user */ processRequest(req) { @@ -84,7 +82,7 @@ class WebSocket { Object.assign(req, data); this.logger.debug(`ID ${data.id} Processing "${req.getCommand()}"`); // Check whether callback exists - if (this.callbackArray.hasOwnProperty(req.getCommand())) { + if (Object.prototype.hasOwnProperty.call(this.callbackArray, req.getCommand())) { const res = this.callbackArray[req.getCommand()](req); // Verify that response is type of WebSocketMessage if (res && res.constructor.name === 'WebSocketMessage') { @@ -109,7 +107,7 @@ class WebSocket { * @param {object} request - connection request */ onconnection(client, request) { - const token = url.parse(request.url, true).query.token; + const { token } = url.parse(request.url, true).query; let decoded; try { decoded = this.http.o2TokenService.verify(token); @@ -119,10 +117,12 @@ class WebSocket { return; } client.id = decoded.id; - client.send(JSON.stringify({command: 'authed', id: client.id})); + client.send(JSON.stringify({ command: 'authed', id: client.id })); client.on('message', (message) => this.onmessage(message, client)); client.on('close', () => this.onclose(client)); - client.on('pong', () => client.isAlive = true); + client.on('pong', () => { + client.isAlive = true; + }); client.on('error', (err) => this.logger.error(`Connection ${err.code}`)); } @@ -138,7 +138,7 @@ class WebSocket { .then((parsed) => { // 2. Check if its message filter (no auth required) if (parsed.getCommand() == 'filter' && parsed.getPayload()) { - client.filter = new Function('return ' + parsed.getPayload())(); + client.filter = new Function(`return ${parsed.getPayload()}`)(); } // 3. Get reply if callback exists this.processRequest(parsed) @@ -198,7 +198,7 @@ class WebSocket { /** * Broadcasts the message to all connected clients * The message must match client's filter (if filter is set) - * @param {WebSocketMessage} message + * @param {WebSocketMessage} message - message to be broadcasted */ broadcast(message) { this.server.clients.forEach((client) => { @@ -206,11 +206,11 @@ class WebSocket { // Handle function execution error, filter comes from WS try { if (!client.filter(message)) { - return; // don't send + return; // Don't send } } catch (error) { this.logger.error(`Client's filter corrupted, skipping broadcast: ${error}`); - return; // don't send + return; // Don't send } } client.send(JSON.stringify(message.json)); @@ -220,7 +220,7 @@ class WebSocket { /** * Broadcasts messages to all connected clients. - * @param {WebSocketMessage} message + * @param {WebSocketMessage} message - message to be broadcasted */ unfilteredBroadcast(message) { this.server.clients.forEach((client) => client.send(JSON.stringify(message.json))); diff --git a/Framework/Frontend/js/src/BrowserStorage.js b/Framework/Frontend/js/src/BrowserStorage.js index 5bf09f01f..5791bb326 100644 --- a/Framework/Frontend/js/src/BrowserStorage.js +++ b/Framework/Frontend/js/src/BrowserStorage.js @@ -10,9 +10,9 @@ * In applying this license CERN does not waive the privileges and immunities * granted to it by virtue of its status as an Intergovernmental Organization * or submit itself to any jurisdiction. -*/ + */ -/* global: window */ +/* Global: window */ /** * Interface to be used for local & session storage @@ -25,7 +25,7 @@ export default class BrowserStorage { /** * Creates a BrowserStorage instance which uses `label` as a prefix for all keys - * @param {string} label + * @param {string} label - prefix for all keys */ constructor(label) { this.label = label; @@ -35,7 +35,7 @@ export default class BrowserStorage { /** * Method to remove item by key from `localStorage` - * @param {string} key + * @param {string} key - key to remove */ removeLocalItem(key) { if (this._isParameterValid(key)) { @@ -45,7 +45,7 @@ export default class BrowserStorage { /** * Method to remove item by key from `sessionStorage` - * @param {string} key + * @param {string} key - key to remove */ removeSessionItem(key) { if (this._isParameterValid(key)) { @@ -54,8 +54,8 @@ export default class BrowserStorage { } /** - * Method to clear `localStorage` - */ + * Method to clear `localStorage` + */ clearLocalStorage() { this.localStorage.clear(); } @@ -70,8 +70,8 @@ export default class BrowserStorage { /** * Method to return the value as JSON from `localStorage` based on key * Returns `null` if not found - * @param {string} key - * @return {boolean} + * @param {string} key - key to search for + * @return {object} - value as JSON */ getLocalItem(key) { return this._getItemAsJSON(key, 'localStorage'); @@ -80,8 +80,8 @@ export default class BrowserStorage { /** * Method to return the value as JSON from `sessionStorage` based on key * Returns `null` if not found - * @param {string} key - * @return {boolean} + * @param {string} key - key to search for + * @return {object} - value as JSON */ getSessionItem(key) { return this._getItemAsJSON(key, 'sessionStorage'); @@ -90,9 +90,9 @@ export default class BrowserStorage { /** * Method to return the value as JSON from storage based on key * Returns `null` if not found - * @param {string} key - * @param {string} locationLabel - * @return {boolean} + * @param {string} key - key to search for + * @param {string} locationLabel - 'localStorage' or 'sessionStorage' + * @return {boolean} - value as JSON */ _getItemAsJSON(key, locationLabel) { if (this._isParameterValid(key)) { @@ -110,9 +110,9 @@ export default class BrowserStorage { /** * Method to set (key, value) in `sessionStorage`. * Returns boolean if successful or not - * @param {string} key - * @param {object} value - * @return {boolean} + * @param {string} key - key to set + * @param {object} value - value to set + * @return {boolean} - true if successful, false otherwise */ setSessionItem(key, value) { return this._setItem(key, value, 'sessionStorage'); @@ -121,9 +121,9 @@ export default class BrowserStorage { /** * Method to set (key, value) in `localStorage`. * Returns boolean if successful or not - * @param {string} key - * @param {object} value - * @return {boolean} + * @param {string} key - key to set + * @param {object} value - value to set + * @return {boolean} - true if successful, false otherwise */ setLocalItem(key, value) { return this._setItem(key, value, 'localStorage'); @@ -132,10 +132,10 @@ export default class BrowserStorage { /** * Method to set item in browser storage. * Returns boolean if successful or not - * @param {string} key - * @param {Object} value - * @param {string} locationLabel - * @return {boolean} + * @param {string} key - key to set + * @param {Object} value - value to set + * @param {string} locationLabel - 'localStorage' or 'sessionStorage' + * @return {boolean} - true if successful, false otherwise */ _setItem(key, value, locationLabel) { const valueAsString = JSON.stringify(value); @@ -156,8 +156,8 @@ export default class BrowserStorage { /** * Method to check if a passed value is of type string and contains non-white characters. - * @param {string} parameter - * @return {boolean} + * @param {string} parameter - value to check + * @return {boolean} - true if valid, false otherwise */ _isParameterValid(parameter) { if (!parameter || typeof parameter !== 'string' || parameter.trim().length === 0) { diff --git a/Framework/Frontend/js/src/EventEmitter.js b/Framework/Frontend/js/src/EventEmitter.js index 76bdcc751..b2543f8b1 100644 --- a/Framework/Frontend/js/src/EventEmitter.js +++ b/Framework/Frontend/js/src/EventEmitter.js @@ -10,7 +10,7 @@ * In applying this license CERN does not waive the privileges and immunities * granted to it by virtue of its status as an Intergovernmental Organization * or submit itself to any jurisdiction. -*/ + */ /** * Class EventEmitter for event-driven architecture @@ -48,7 +48,7 @@ class EventEmitter { */ removeListener(eventName, listener) { if (!this.listeners.has(eventName)) { - // eventName not found + // EventName not found return this; } @@ -56,7 +56,7 @@ class EventEmitter { const index = listeners.indexOf(listener); if (index === -1) { - // listener not found + // Listener not found return this; } @@ -68,13 +68,13 @@ class EventEmitter { /** * Synchronously calls each of the listeners registered for the event named eventName, * in the order they were registered, passing the supplied arguments to each - * @param {string} eventName - * @param {any} ...args - arguments to be passed to the listeners + * @param {string} eventName - the name of the event + * @param {object} args - arguments to be passed to the listeners * @return {boolean} - Returns true if the event had listeners, false otherwise. */ emit(eventName, ...args) { if (!this.listeners.has(eventName)) { - // eventName not found + // EventName not found return false; } diff --git a/Framework/Frontend/js/src/Loader.js b/Framework/Frontend/js/src/Loader.js index 21f3eb40c..884d53ce6 100644 --- a/Framework/Frontend/js/src/Loader.js +++ b/Framework/Frontend/js/src/Loader.js @@ -10,7 +10,7 @@ * In applying this license CERN does not waive the privileges and immunities * granted to it by virtue of its status as an Intergovernmental Organization * or submit itself to any jurisdiction. -*/ + */ import Observable from './Observable.js'; import fetchClient from './fetchClient.js'; @@ -54,7 +54,7 @@ class Loader extends Observable { /** * Register a promise and increase `activePromises` by 1, * on promise ends, decrease by 1. - * @param {Promise} promise + * @param {Promise} promise - promise that is to be watched */ watchPromise(promise) { this.activePromises++; @@ -105,9 +105,9 @@ class Loader extends Observable { method: 'POST', headers: { Accept: 'application/json', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - body: JSON.stringify(body) + body: JSON.stringify(body), }; return await this._request(url, options, originalMessage); @@ -156,34 +156,33 @@ class Loader extends Observable { let response; try { response = await request; - } catch (error) { - // handle connection error - const message = `Connection to server failed, please try again`; - return new AjaxResult(false, 0, {message}); + } catch { + // Handle connection error + const message = 'Connection to server failed, please try again'; + return new AjaxResult(false, 0, { message }); } - // handle server error- + // Handle server error- if (!response.ok) { let upstreamMessage = {}; try { upstreamMessage = await response.json(); - } catch (e) { + } catch { upstreamMessage.message = 'Server provided no deatils'; } - // eslint-disable-next-line const message = originalMessage ? upstreamMessage.message : `Request to server failed (${response.status} ${response.statusText}): ${upstreamMessage.message}`; - return new AjaxResult(false, response.status, {message}); + return new AjaxResult(false, response.status, { message }); } let result; try { result = await response.json(); - } catch (error) { - // handle JSON error - const message = `Parsing result from server failed`; - return new AjaxResult(false, response.status, {message}); + } catch { + // Handle JSON error + const message = 'Parsing result from server failed'; + return new AjaxResult(false, response.status, { message }); } // OK! diff --git a/Framework/Frontend/js/src/Notification.js b/Framework/Frontend/js/src/Notification.js index 21efff824..b70ce520e 100644 --- a/Framework/Frontend/js/src/Notification.js +++ b/Framework/Frontend/js/src/Notification.js @@ -10,10 +10,10 @@ * In applying this license CERN does not waive the privileges and immunities * granted to it by virtue of its status as an Intergovernmental Organization * or submit itself to any jurisdiction. -*/ + */ import Observable from './Observable.js'; -import {h} from './renderer.js'; +import { h } from './renderer.js'; import switchCase from './switchCase.js'; /** @@ -47,8 +47,8 @@ export class Notification extends Observable { this.message = ''; this.type = 'primary'; - this.state = 'hidden'; // shown, hidden - this.timerId = 0; // timer to auto-hide notification + this.state = 'hidden'; // Shown, hidden + this.timerId = 0; // Timer to auto-hide notification } /** @@ -70,14 +70,14 @@ export class Notification extends Observable { duration = duration || 5000; - // clear previous message countdown + // Clear previous message countdown clearTimeout(this.timerId); this.message = message; this.type = type; this.state = 'shown'; - // auto-hide after duration + // Auto-hide after duration if (duration !== Infinity) { this.timerId = setTimeout(() => { this.hide(); @@ -102,8 +102,8 @@ export class Notification extends Observable { /** * Shows notification according to `notificationInstance`. Because of its absolute position it should * be placed as first element inside body. - * @param {Notification} notificationInstance - * @return {vnode} + * @param {Notification} notificationInstance - instance of Notification + * @return {vnode} - virtual node to render notification * @example * import {mount, h, Notification, notification} from '../../Frontend/js/src/index.js'; * @@ -125,12 +125,12 @@ export class Notification extends Observable { export const notification = (notificationInstance) => h('.notification.text-no-select.level4.text-light', { }, h('span.notification-content.br2.p2.shadow-level4', { - // className: notificationInstance.message && (notificationInstance.state === 'shown' ? 'notification-open' : 'notification-close'), + // ClassName: notificationInstance.message && (notificationInstance.state === 'shown' ? 'notification-open' : 'notification-close'), onclick: () => notificationInstance.hide(), - className: switchCase(notificationInstance.type, { + className: `${switchCase(notificationInstance.type, { primary: 'white bg-primary', success: 'white bg-success', warning: 'white bg-warning', danger: 'white bg-danger', - }) + ' ' + (notificationInstance.state === 'shown' ? 'notification-open' : 'notification-close') + })} ${notificationInstance.state === 'shown' ? 'notification-open' : 'notification-close'}`, }, notificationInstance.message)); diff --git a/Framework/Frontend/js/src/Observable.js b/Framework/Frontend/js/src/Observable.js index dcbaae252..1b39363b9 100644 --- a/Framework/Frontend/js/src/Observable.js +++ b/Framework/Frontend/js/src/Observable.js @@ -10,7 +10,7 @@ * In applying this license CERN does not waive the privileges and immunities * granted to it by virtue of its status as an Intergovernmental Organization * or submit itself to any jurisdiction. -*/ + */ /** * Simple Observable class to notify others listening for changes @@ -40,9 +40,7 @@ class Observable { * @param {function} callback - the callback to remove */ unobserve(callback) { - this.observers = this.observers.filter((observer) => { - return observer !== callback; - }); + this.observers = this.observers.filter((observer) => observer !== callback); } /** diff --git a/Framework/Frontend/js/src/QueryRouter.js b/Framework/Frontend/js/src/QueryRouter.js index 32ee2c6ab..0d6426139 100644 --- a/Framework/Frontend/js/src/QueryRouter.js +++ b/Framework/Frontend/js/src/QueryRouter.js @@ -10,7 +10,7 @@ * In applying this license CERN does not waive the privileges and immunities * granted to it by virtue of its status as an Intergovernmental Organization * or submit itself to any jurisdiction. -*/ + */ /* Global: window */ @@ -119,7 +119,8 @@ class QueryRouter extends Observable { const entries = url.searchParams.entries(); this.params = {}; for (const pair of entries) { - this.params[pair[0]] = pair[1]; + const [, secondPair] = pair; + this.params[pair[0]] = secondPair; } this.notify(); } @@ -129,24 +130,24 @@ class QueryRouter extends Observable { * @param {object} e - DOM event */ handleLinkEvent(e) { - // the element to which the handler is attached, not the one firing + // The element to which the handler is attached, not the one firing const target = e.currentTarget; - // user asked download, new tab, new window + // User asked download, new tab, new window const specialOpening = e.altKey || e.metaKey || e.ctrlKey || e.shiftKey; const forceNewTab = target.target === '_blank'; const differentOrigin = target.origin !== window.location.origin; if (specialOpening || forceNewTab || differentOrigin) { - // let the browser handle the event + // Let the browser handle the event return; } - // stop other listeners to handle the event bubbling in the DOM tree + // Stop other listeners to handle the event bubbling in the DOM tree e.preventDefault(); - // push new url on the bar address + // Push new url on the bar address this.history.pushState({}, '', target.href); this._handleLocationChange(); @@ -154,7 +155,7 @@ class QueryRouter extends Observable { /** * Get the current URL object containing searchParams, pathname, etc. - * @return {URL} + * @return {URL} - URL object */ getUrl() { return new URL(this.location); @@ -176,7 +177,7 @@ class QueryRouter extends Observable { } if (!silent) { - // replaceState and pushState cannot be listen so we trigger manually that location changed + // ReplaceState and pushState cannot be listen so we trigger manually that location changed this._handleLocationChange(); } } diff --git a/Framework/Frontend/js/src/RemoteData.js b/Framework/Frontend/js/src/RemoteData.js index 192d87c90..ade27f11c 100644 --- a/Framework/Frontend/js/src/RemoteData.js +++ b/Framework/Frontend/js/src/RemoteData.js @@ -62,7 +62,6 @@ export class RemoteData { * @template T return type of the callbacks * * @param {MatchClauses} clauses the match clauses to apply - * @return {T} result of the function associated to clause * @example * import {RemoteData} from '/js/src/index.js'; * var item = RemoteData.NotAsked(); @@ -141,7 +140,7 @@ export class RemoteData { /** * Test if current kind is a `NotAsked` - * @return {boolean} + * @return {boolean} - true if current kind is a `NotAsked` * @deprecated use {@see RemoteData#match} or {@see RemoteData#apply} instead */ isNotAsked() { @@ -150,7 +149,7 @@ export class RemoteData { /** * Test is current kind is a `Loading` - * @return {boolean} + * @return {boolean} - true if current kind is a `Loading` * @example * @deprecated use {@see RemoteData#match} or {@see RemoteData#apply} instead */ @@ -161,7 +160,7 @@ export class RemoteData { /** * Test is current kind is a `Success` * @deprecated use {@see RemoteData#match} or {@see RemoteData#apply} instead - * @return {boolean} + * @return {boolean} - true if current kind is a `Success` */ isSuccess() { return false; @@ -170,7 +169,7 @@ export class RemoteData { /** * States if current kind is a `Failure` * @deprecated use {@see RemoteData#match} or {@see RemoteData#apply} instead - * @return {boolean} + * @return {boolean} - true if current kind is a `Failure` */ isFailure() { return false; @@ -182,7 +181,7 @@ export class RemoteData { * @template P * @template E * - * @return {RemoteData} + * @return {RemoteData} - not asked remote data object * @static */ static notAsked() { @@ -190,6 +189,7 @@ export class RemoteData { } /** + * RemoteData for NotAsked * @deprecated use {@see RemoteData#notAsked} */ static NotAsked() { @@ -202,7 +202,7 @@ export class RemoteData { * @template P * @template E * - * @return {RemoteData} + * @return {RemoteData} - loading remote data object * @static */ static loading() { @@ -210,6 +210,7 @@ export class RemoteData { } /** + * RemoteData for Loading * @deprecated use {@see RemoteData#loading} * @static */ @@ -223,8 +224,8 @@ export class RemoteData { * @template P * @template E * - * @param {P} payload - * @return {RemoteData} + * @param {P} payload - to be set as payload + * @return {RemoteData} - success remote data with payload * @static */ static success(payload) { @@ -232,6 +233,8 @@ export class RemoteData { } /** + * RemoteData for Success + * @param {object} payload - to be set as payload * @deprecated use {@see RemoteData#success} * @static */ @@ -245,8 +248,8 @@ export class RemoteData { * @template P * @template E * - * @param {E} error - * @return {RemoteData} + * @param {E} error - to be set + * @return {RemoteData} - remote data with error * @static */ static failure(error) { @@ -254,7 +257,9 @@ export class RemoteData { } /** - * @deprecated use {@see RemoteData#failure} + * Remote data for Failure cases + * @param {object} payload - to be set + * @deprecated use @see RemoteData#failure * @static */ static Failure(payload) { @@ -267,10 +272,9 @@ export class RemoteData { * * @template P * @template E - * @extends RemoteData + * @extends RemoteData */ export class NotAskedRemoteData extends RemoteData { - // eslint-disable-next-line require-jsdoc /** * @inheritDoc */ @@ -290,7 +294,7 @@ export class NotAskedRemoteData extends RemoteData { * @inheritDoc */ get kind() { - return "NotAsked"; + return 'NotAsked'; } } @@ -299,10 +303,9 @@ export class NotAskedRemoteData extends RemoteData { * * @template P * @template E - * @extends RemoteData + * @extends RemoteData */ export class LoadingRemoteData extends RemoteData { - // eslint-disable-next-line require-jsdoc /** * @inheritDoc */ @@ -322,7 +325,7 @@ export class LoadingRemoteData extends RemoteData { * @inheritDoc */ get kind() { - return "Loading"; + return 'Loading'; } } @@ -331,7 +334,7 @@ export class LoadingRemoteData extends RemoteData { * * @template P * @template E - * @extends RemoteData + * @extends RemoteData */ export class SuccessRemoteData extends RemoteData { /** @@ -343,7 +346,6 @@ export class SuccessRemoteData extends RemoteData { this._payload = payload; } - // eslint-disable-next-line require-jsdoc /** * @inheritDoc */ @@ -371,7 +373,7 @@ export class SuccessRemoteData extends RemoteData { * @inheritDoc */ get kind() { - return "Success"; + return 'Success'; } } @@ -380,7 +382,7 @@ export class SuccessRemoteData extends RemoteData { * * @template P * @template E - * @extends RemoteData + * @extends RemoteData */ export class FailureRemoteData extends RemoteData { /** @@ -392,7 +394,6 @@ export class FailureRemoteData extends RemoteData { this._error = error; } - // eslint-disable-next-line require-jsdoc /** * @inheritDoc */ @@ -420,6 +421,6 @@ export class FailureRemoteData extends RemoteData { * @inheritDoc */ get kind() { - return "Failure"; + return 'Failure'; } } diff --git a/Framework/Frontend/js/src/WebSocketClient.js b/Framework/Frontend/js/src/WebSocketClient.js index 4c5731b7b..90a3e0fb7 100644 --- a/Framework/Frontend/js/src/WebSocketClient.js +++ b/Framework/Frontend/js/src/WebSocketClient.js @@ -10,64 +10,64 @@ * In applying this license CERN does not waive the privileges and immunities * granted to it by virtue of its status as an Intergovernmental Organization * or submit itself to any jurisdiction. -*/ + */ -/* global: window */ +/* Global: window */ import sessionService from './sessionService.js'; import EventEmitter from './EventEmitter.js'; -const location = window.location; +const { location } = window; /** - * `open` event. - * - * @event WebSocketClient#open - */ + * `open` event. + * + * @event WebSocketClient#open + */ /** - * `error` event. - * See `close` event for more details on why. - * - * @event WebSocketClient#error - * @type {WebSocketMessage} - * @property {number} code - * @property {string} message - * @property {object} payload - */ + * `error` event. + * See `close` event for more details on why. + * + * @event WebSocketClient#error + * @type {WebSocketMessage} + * @property {number} code + * @property {string} message + * @property {object} payload + */ /** - * `close` event. - * https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent - * - * @event WebSocketClient#close - * @type {CloseEvent} - * @property {string} reason - * @property {number} code - */ + * `close` event. + * https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent + * + * @event WebSocketClient#close + * @type {CloseEvent} + * @property {string} reason + * @property {number} code + */ /** - * `authed` event when WSClient is authentificated by server - * and can process incoming requests. - * - * @event WebSocketClient#authed - */ + * `authed` event when WSClient is authentificated by server + * and can process incoming requests. + * + * @event WebSocketClient#authed + */ /** - * `token` event when new auth token has been made - * sessionService is also refreshed. - * - * @event WebSocketClient#token - */ + * `token` event when new auth token has been made + * sessionService is also refreshed. + * + * @event WebSocketClient#token + */ /** - * `command` event when a custom command is received. - * - * @event WebSocketClient#command - * @type {WebSocketMessage} - * @property {string} command - * @property {object} payload - */ + * `command` event when a custom command is received. + * + * @event WebSocketClient#command + * @type {WebSocketMessage} + * @property {string} command + * @property {object} payload + */ /** * Encapsulate WebSocket and provides the endpoint, filtering stream and authentification status. @@ -139,18 +139,18 @@ class WebSocketClient extends EventEmitter { try { parsed = JSON.parse(e.data); - } catch (e) { - throw new Error(`unable to parse ws data`); + } catch { + throw new Error('unable to parse ws data'); } - // handling authentification success + // Handling authentification success if (parsed.command == 'authed') { this.authed = true; this.emit('authed'); return; } - // handling token refresh error + // Handling token refresh error if (parsed.code == 440) { const session = sessionService.get(); session.token = parsed.payload.newtoken; @@ -158,20 +158,20 @@ class WebSocketClient extends EventEmitter { return; } - // handling request error + // Handling request error if (parsed.code >= 400) { this.emit('error', parsed); return; } - // fire parsed and valid message to be used by clients + // Fire parsed and valid message to be used by clients this.emit('command', parsed); } /** * Send plain object to server, it must implement the Message interface (command field), * you must also wait the connection to be authentificated (authed property and event). - * @param {object} message + * @param {object} message - Message to be sent to server */ sendMessage(message) { if (!this.authed) { @@ -188,12 +188,12 @@ class WebSocketClient extends EventEmitter { /** * Send the stream filter to server - * @param {function} filter + * @param {function} filter - Filter function to be sent to server */ setFilter(filter) { const message = { command: 'filter', - payload: filter.toString() + payload: filter.toString(), }; this.sendMessage(message); } diff --git a/Framework/Frontend/js/src/chart.js b/Framework/Frontend/js/src/chart.js index 277283451..6400df5ed 100644 --- a/Framework/Frontend/js/src/chart.js +++ b/Framework/Frontend/js/src/chart.js @@ -10,24 +10,24 @@ * In applying this license CERN does not waive the privileges and immunities * granted to it by virtue of its status as an Intergovernmental Organization * or submit itself to any jurisdiction. -*/ + */ -import {h} from './renderer.js'; +import { h } from './renderer.js'; /** * Displays time-series based chart of recent data * with a sliding window. Time scale (x) must be specified and * value scale (y) is automatic to fill height. * Value: {value:number, timestamp:number:ms} - * @param {Object} userOptions - all options to draw the chart - * @param {number} width - size of canvas - * @param {number} height - size of canvas - * @param {Array} series - timestamp in ms - * @param {string} title - to be printed on corner bottom left - * @param {number} timeWindow - ms/div for x axis, div is half height - * @param {string} colorPrimary - color of curve - * @param {string} colorSecondary - color of axis and labels - * @param {string} background - color of background + * @param {object} userOptions - all options to draw the chart + * @param {number} userOptions.width - size of canvas + * @param {number} userOptions.height - size of canvas + * @param {Array} userOptions.series - timestamp in ms + * @param {string} userOptions.title - to be printed on corner bottom left + * @param {number} userOptions.timeWindow - ms/div for x axis, div is half height + * @param {string} userOptions.colorPrimary - color of curve + * @param {string} userOptions.colorSecondary - color of axis and labels + * @param {string} userOptions.background - color of background * @return {vnode} canvas element as a virtual node * @example * chartTimeSeries({ @@ -48,18 +48,18 @@ export function chartTimeSeries(userOptions) { colorPrimary: 'black', colorSecondary: 'gray', title: '', - devicePixelRatio: window.devicePixelRatio, // default=1, retina=2, higher=3 - timeWindow: 1000, // how many ms to represent in the width available + devicePixelRatio: window.devicePixelRatio, // Default=1, retina=2, higher=3 + timeWindow: 1000, // How many ms to represent in the width available }; - const options = Object.assign({}, defaults, userOptions); + const options = { ...defaults, ...userOptions }; // Canvas is 2x bigger than element, to handle high resolution (retina) return h('canvas', { width: options.width * options.devicePixelRatio, height: options.height * options.devicePixelRatio, style: { - width: options.width + 'px', - height: options.height + 'px', + width: `${options.width}px`, + height: `${options.height}px`, }, oncreate: (vnode) => draw(vnode.dom, options), onupdate: (vnode) => draw(vnode.dom, options), @@ -68,12 +68,12 @@ export function chartTimeSeries(userOptions) { /** * Draw chartTimeSeries to the specified dom element with options - * @param {DOMElement} dom + * @param {DOMElement} dom - canvas element * @param {Object} options - See chartTimeSeries options */ function draw(dom, options) { const ctx = dom.getContext('2d'); - ctx.save(); // save default scale + ctx.save(); // Save default scale ctx.scale(options.devicePixelRatio, options.devicePixelRatio); ctx.clearRect(0, 0, options.width, options.height); ctx.beginPath(); @@ -88,18 +88,16 @@ function draw(dom, options) { const maxY = maxValue.toExponential(2); const legendText = `minY=${minY}, maxY=${maxY}, ms/div=${options.timeWindow}ms`; - drawLegend(ctx, options.title, legendText, 0, options.height - 16, - options.width, options.height, options.colorSecondary); + drawLegend(ctx, options.title, legendText, 0, options.height - 16, options.width, options.height, options.colorSecondary); drawGrid(ctx, options.width, options.height - 16, options.colorSecondary); - drawCurve(ctx, options.series, maxValue, minValue, - options.width, options.height - 16, options.colorPrimary, options.timeWindow); + drawCurve(ctx, options.series, maxValue, minValue, options.width, options.height - 16, options.colorPrimary, options.timeWindow); - ctx.restore(); // restore default scale + ctx.restore(); // Restore default scale } /** * Part of chartTimeSeries, draw the title and scaling - * @param {CanvasRenderingContext2D} ctx + * @param {CanvasRenderingContext2D} ctx - canvas context * @param {string} titleText - title at bottom left * @param {string} legendText - legend at bottom right * @param {number} left - position of legend @@ -123,7 +121,7 @@ function drawLegend(ctx, titleText, legendText, left, top, width, height, color) /** * Part of chartTimeSeries, draw the axis - * @param {CanvasRenderingContext2D} ctx + * @param {CanvasRenderingContext2D} ctx - canvas context * @param {number} width - width of the available area * @param {number} height - height of the available area * @param {string} color - color of axis @@ -133,22 +131,22 @@ function drawGrid(ctx, width, height, color) { ctx.strokeStyle = color; ctx.setLineDash([5, 5]); - // top + // Top ctx.moveTo(0, 1); ctx.lineTo(width, 1); ctx.stroke(); - // middle + // Middle ctx.moveTo(0, height / 2); ctx.lineTo(width, height / 2); ctx.stroke(); - // bottom + // Bottom ctx.moveTo(0, height); ctx.lineTo(width, height); ctx.stroke(); - // verticals (to form squares) + // Verticals (to form squares) for (let x = width; x >= 0; x -= height / 2) { ctx.moveTo(x, 0); ctx.lineTo(x, height); @@ -160,7 +158,7 @@ function drawGrid(ctx, width, height, color) { /** * Part of chartTimeSeries, draw the curve - * @param {CanvasRenderingContext2D} ctx + * @param {CanvasRenderingContext2D} ctx - canvas context * @param {Array} series - data * @param {number} max - max value of series * @param {number} min - min value of series @@ -171,26 +169,28 @@ function drawGrid(ctx, width, height, color) { */ function drawCurve(ctx, series, max, min, width, height, color, timeWindow) { if (series.length === 0) { - // nothing to draw, exit now + // Nothing to draw, exit now return; } - // init path + // Init path ctx.beginPath(); ctx.strokeStyle = color; - const diff = max - min || 1; // relative range of Y axis, div zero avoided with 1 + const diff = max - min || 1; // Relative range of Y axis, div zero avoided with 1 let firstPoint = true; - series.sort(sortByTimestamp); // index 0 is older, higher is newer - const divSize = height / 2; // pixels per division for X axis + series.sort(sortByTimestamp); // Index 0 is older, higher is newer + const divSize = height / 2; // Pixels per division for X axis const numberOfDivs = width / divSize; // # of division on X axis for the space available - const maxTimestamp = Date.now(); // maximum value on X axis (timestamp) - const totalTimeWindow = numberOfDivs * timeWindow; // how much time represented on the plot (ms) - const minTimestamp = maxTimestamp - totalTimeWindow; // minimum value on X axis (timestamp) + const maxTimestamp = Date.now(); // Maximum value on X axis (timestamp) + const totalTimeWindow = numberOfDivs * timeWindow; // How much time represented on the plot (ms) + const minTimestamp = maxTimestamp - totalTimeWindow; // Minimum value on X axis (timestamp) - // draw points starting from the most recent (right) to older (left) - // until curbe overflow avaialble space or until there is no more points + /* + * Draw points starting from the most recent (right) to older (left) + * Until curbe overflow available space or until there is no more points + */ for (let pointIndex = series.length - 1; pointIndex >= 0; pointIndex--) { const point = series[pointIndex]; if (!point) { @@ -198,14 +198,14 @@ function drawCurve(ctx, series, max, min, width, height, color, timeWindow) { } let y = point.value; - y = y - min; // position of minimal value centered on horizontal axis (bottom) - y = y / diff * height; // scale min and max to fill height - y = height - y; // reverse axis, negative on right, positive on left + y = y - min; // Position of minimal value centered on horizontal axis (bottom) + y = y / diff * height; // Scale min and max to fill height + y = height - y; // Reverse axis, negative on right, positive on left let x = point.timestamp; - x = maxTimestamp - x; // position of max time centered on vertical axis - x = x / totalTimeWindow * width; // scale timeWindow to fill width - x = width - x; // reverse axis, negative on right, positive on left + x = maxTimestamp - x; // Position of max time centered on vertical axis + x = x / totalTimeWindow * width; // Scale timeWindow to fill width + x = width - x; // Reverse axis, negative on right, positive on left firstPoint ? ctx.moveTo(x, y) : ctx.lineTo(x, y); firstPoint = false; @@ -222,27 +222,26 @@ function drawCurve(ctx, series, max, min, width, height, color, timeWindow) { * Comparaison function to sort points by `timestamp` field * @param {Object} pointA - {value:number, timestamp:number:ms} * @param {Object} pointB - {value:number, timestamp:number:ms} - * @return {number} + * @return {number} - difference between timestamps */ const sortByTimestamp = (pointA, pointB) => pointA.timestamp - pointB.timestamp; /** * Find the maximum '.value' of array of points - * @param {Array.} points - * @return {number} + * @param {Array.} points - {value:number, timestamp:number:ms} + * @return {number} - maximum value */ const maxOf = (points) => points.reduce( (max, point) => point.value > max ? point.value : max, - -Infinity + -Number(Infinity), ); /** * Find the minimum '.value' of array of points - * @param {Array.} points - * @return {number} + * @param {Array.} points - {value:number, timestamp:number:ms} + * @return {number} - minimum value */ const minOf = (points) => points.reduce( (min, point) => point.value < min ? point.value : min, - +Infinity + +Number(Infinity), ); - diff --git a/Framework/Frontend/js/src/fetchClient.js b/Framework/Frontend/js/src/fetchClient.js index 1328a4251..c6ef7999e 100644 --- a/Framework/Frontend/js/src/fetchClient.js +++ b/Framework/Frontend/js/src/fetchClient.js @@ -10,19 +10,19 @@ * In applying this license CERN does not waive the privileges and immunities * granted to it by virtue of its status as an Intergovernmental Organization * or submit itself to any jurisdiction. -*/ + */ -/* global: window */ +/* Global: window */ import sessionService from './sessionService.js'; -const location = window.location; +const { location } = window; /** * Extends the fetch() function by adding the session token in the request * by taking it from sessionService transparently for developer. * See https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API - * @param {string} URL + * @param {...any} args - arguments to pass to fetch * @return {object} options - method, etc. * @example * import {fetchClient} from '/js/src/index.js'; @@ -43,8 +43,10 @@ function fetchClient(...args) { const session = sessionService.get(); - // Parse the URI provided - // location brings the base if first arg is relative + /* + * Parse the URI provided + * Location brings the base if first arg is relative + */ const url = new URL(args[0], location); // Inject the token in the query string diff --git a/Framework/Frontend/js/src/formatter/formatTimeDuration.js b/Framework/Frontend/js/src/formatter/formatTimeDuration.js index f32432430..0d9c359ad 100644 --- a/Framework/Frontend/js/src/formatter/formatTimeDuration.js +++ b/Framework/Frontend/js/src/formatter/formatTimeDuration.js @@ -10,7 +10,7 @@ * granted to it by virtue of its status as an Intergovernmental Organization * or submit itself to any jurisdiction. */ -import {splitDuration} from '../utilities/durationUtils.js'; +import { splitDuration } from '../utilities/durationUtils.js'; /** * Format a given duration (in milliseconds) in the format HH:MM:SS @@ -24,9 +24,7 @@ export const formatTimeDuration = (duration) => { return '-'; } - const {hours, minutes, seconds} = splitDuration(duration); - - // eslint-disable-next-line require-jsdoc + const { hours, minutes, seconds } = splitDuration(duration); const formatNumber = (number) => `${number}`.padStart(2, '0'); return `${formatNumber(hours)}:${formatNumber(minutes)}:${formatNumber(seconds)}`; diff --git a/Framework/Frontend/js/src/icons.js b/Framework/Frontend/js/src/icons.js index 57b81083c..f7d7b5173 100644 --- a/Framework/Frontend/js/src/icons.js +++ b/Framework/Frontend/js/src/icons.js @@ -10,225 +10,224 @@ * In applying this license CERN does not waive the privileges and immunities * granted to it by virtue of its status as an Intergovernmental Organization * or submit itself to any jurisdiction. -*/ + */ -import {h} from './renderer.js'; - -/* eslint max-len:0, require-jsdoc:0 */ +import { h } from './renderer.js'; +/* eslint-disable @stylistic/js/max-len */ // SVG icon wrapper -export const icon = (svg, className = 'fill-primary') => h('svg.icon', {className: className, viewBox: '0 0 8 8'}, svg); +export const icon = (svg, className = 'fill-primary') => h('svg.icon', { className: className, viewBox: '0 0 8 8' }, svg); // SVG icons -export const iconAccountLogin = () => icon(h('path', {d: 'M3 0v1h4v5h-4v1h5v-7h-5zm1 2v1h-4v1h4v1l2-1.5-2-1.5z'})); -export const iconAccountLogout = () => icon(h('path', {d: 'M3 0v1h4v5h-4v1h5v-7h-5zm-1 2l-2 1.5 2 1.5v-1h4v-1h-4v-1z'})); -export const iconActionRedo = () => icon(h('path', {d: 'M3.5 1c-1.93 0-3.5 1.57-3.5 3.5 0-1.38 1.12-2.5 2.5-2.5s2.5 1.12 2.5 2.5v.5h-1l2 2 2-2h-1v-.5c0-1.93-1.57-3.5-3.5-3.5z'})); -export const iconActionUndo = () => icon(h('path', {d: 'M4.5 1c-1.93 0-3.5 1.57-3.5 3.5v.5h-1l2 2 2-2h-1v-.5c0-1.38 1.12-2.5 2.5-2.5s2.5 1.12 2.5 2.5c0-1.93-1.57-3.5-3.5-3.5z'})); -export const iconAlignCenter = () => icon(h('path', {d: 'M0 0v1h8v-1h-8zm1 2v1h6v-1h-6zm-1 2v1h8v-1h-8zm1 2v1h6v-1h-6z'})); -export const iconAlignLeft = () => icon(h('path', {d: 'M0 0v1h8v-1h-8zm0 2v1h6v-1h-6zm0 2v1h8v-1h-8zm0 2v1h6v-1h-6z'})); -export const iconAlignRight = () => icon(h('path', {d: 'M0 0v1h8v-1h-8zm2 2v1h6v-1h-6zm-2 2v1h8v-1h-8zm2 2v1h6v-1h-6z'})); -export const iconArrowCircleBottom = () => icon(h('path', {d: 'M4 0c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm-1 1h2v3h2l-3 3-3-3h2v-3z'})); -export const iconArrowCircleLeft = () => icon(h('path', {d: 'M4 0c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm0 1v2h3v2h-3v2l-3-3 3-3z'})); -export const iconArrowCircleRight = () => icon(h('path', {d: 'M4 0c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm0 1l3 3-3 3v-2h-3v-2h3v-2z'})); -export const iconArrowCircleTop = () => icon(h('path', {d: 'M4 0c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm0 1l3 3h-2v3h-2v-3h-2l3-3z'})); -export const iconArrowBottom = () => icon(h('path', {d: 'M3 0v5h-2l2.531 3 2.469-3h-2v-5h-1z'})); -export const iconArrowLeft = () => icon(h('path', {d: 'M3 1l-3 2.531 3 2.469v-2h5v-1h-5v-2z'})); -export const iconArrowRight = () => icon(h('path', {d: 'M5 1v2h-5v1h5v2l3-2.531-3-2.469z'})); -export const iconArrowTop = () => icon(h('path', {d: 'M3.469 0l-2.469 3h2v5h1v-5h2l-2.531-3z'})); -export const iconArrowThickBottom = () => icon(h('path', {d: 'M3 0v5h-2l3.031 3 2.969-3h-2v-5h-2z'})); -export const iconArrowThickLeft = () => icon(h('path', {d: 'M3 1l-3 3.031 3 2.969v-2h5v-2h-5v-2z'})); -export const iconArrowThickRight = () => icon(h('path', {d: 'M5 1v2h-5v2h5v2l3-3.031-3-2.969z'})); -export const iconArrowThickTop = () => icon(h('path', {d: 'M3.969 0l-2.969 3h2v5h2v-5h2l-3.031-3z'})); -export const iconAudioSpectrum = () => icon(h('path', {d: 'M4 0v8h1v-8h-1zm-2 1v6h1v-6h-1zm4 1v4h1v-4h-1zm-6 1v2h1v-2h-1z'})); -export const iconAudio = () => icon(h('path', {d: 'M1.188 1c-.734.722-1.188 1.748-1.188 2.844 0 1.095.454 2.09 1.188 2.813l.688-.719c-.546-.538-.875-1.269-.875-2.094s.329-1.587.875-2.125l-.688-.719zm5.625 0l-.688.719c.552.552.875 1.289.875 2.125 0 .836-.327 1.554-.875 2.094l.688.719c.732-.72 1.188-1.708 1.188-2.813 0-1.104-.459-2.115-1.188-2.844zm-4.219 1.406c-.362.362-.594.889-.594 1.438 0 .548.232 1.045.594 1.406l.688-.719c-.178-.178-.281-.416-.281-.688 0-.272.103-.54.281-.719l-.688-.719zm2.813 0l-.688.719c.183.183.281.434.281.719s-.099.505-.281.688l.688.719c.357-.357.594-.851.594-1.406 0-.555-.236-1.08-.594-1.438z'})); -export const iconBadge = () => icon(h('path', {d: 'M4 0c-1.105 0-2 .895-2 2s.895 2 2 2 2-.895 2-2-.895-2-2-2zm-1 4.813v3.188l1-1 1 1v-3.188c-.31.11-.65.188-1 .188s-.69-.077-1-.188z'})); -export const iconBan = () => icon(h('path', {d: 'M4 0c-2.203 0-4 1.797-4 4 0 2.203 1.797 4 4 4 2.203 0 4-1.797 4-4 0-2.203-1.797-4-4-4zm0 1c.655 0 1.258.209 1.75.563l-4.188 4.188c-.353-.492-.563-1.095-.563-1.75 0-1.663 1.337-3 3-3zm2.438 1.25c.353.492.563 1.095.563 1.75 0 1.663-1.337 3-3 3-.655 0-1.258-.209-1.75-.563l4.188-4.188z'})); -export const iconBarChart = () => icon(h('path', {d: 'M0 0v7h8v-1h-7v-6h-1zm5 0v5h2v-5h-2zm-3 2v3h2v-3h-2z'})); -export const iconBasket = () => icon(h('path', {d: 'M3.969 0c-.127.011-.259.083-.344.188l-2.344 2.813h-1.281v1h1v3.656c0 .18.164.344.344.344h5.313c.18 0 .344-.164.344-.344v-3.656h1v-1h-1.281c-.274-.329-2.387-2.866-2.406-2.875-.105-.09-.216-.136-.344-.125zm.031 1.281l1.438 1.719h-2.875l1.438-1.719zm-1.5 3.719c.28 0 .5.22.5.5v1c0 .28-.22.5-.5.5s-.5-.22-.5-.5v-1c0-.28.22-.5.5-.5zm3 0c.28 0 .5.22.5.5v1c0 .28-.22.5-.5.5s-.5-.22-.5-.5v-1c0-.28.22-.5.5-.5z'})); -export const iconBatteryEmpty = () => icon(h('path', {d: 'M.094 1c-.06 0-.094.034-.094.094v5.813c0 .06.034.094.094.094h6.813c.06 0 .094-.034.094-.094v-1.906h1v-2h-1v-1.906c0-.06-.034-.094-.094-.094h-6.813zm.906 1h5v4h-5v-4z'})); -export const iconBatteryFull = () => icon(h('path', {d: 'M.094 1c-.06 0-.094.034-.094.094v5.813c0 .06.034.094.094.094h6.813c.06 0 .094-.034.094-.094v-1.906h1v-2h-1v-1.906c0-.06-.034-.094-.094-.094h-6.813z'})); -export const iconBeaker = () => icon(h('path', {d: 'M1.344 0a.502.502 0 0 0 .156 1h.5v1.406c-.088.172-1.194 2.313-1.656 3.094-.153.268-.344.612-.344 1.063 0 .383.139.764.406 1.031.26.26.643.406 1.031.406h5.125c.383 0 .764-.139 1.031-.406.26-.26.406-.643.406-1.031 0-.452-.194-.801-.344-1.063-.463-.78-1.568-2.922-1.656-3.094v-1.406h.5a.5.5 0 1 0 0-1h-5a.5.5 0 0 0-.094 0 .502.502 0 0 0-.063 0zm1.656 1h2v1.625l.063.094s.652 1.233 1.219 2.281h-4.563c.567-1.049 1.219-2.281 1.219-2.281l.063-.094v-1.625z'})); -export const iconBell = () => icon(h('path', {d: 'M4 0c-1.1 0-2 .9-2 2 0 1.04-.524 1.976-1.344 2.656-.42.34-.656.824-.656 1.344h8c0-.52-.236-1.004-.656-1.344-.82-.68-1.344-1.616-1.344-2.656 0-1.1-.9-2-2-2zm-1 7c0 .55.45 1 1 1s1-.45 1-1h-2z'})); -export const iconBold = () => icon(h('path', {d: 'M0 0v1c.55 0 1 .45 1 1v4c0 .55-.45 1-1 1v1h5.5c1.38 0 2.5-1.12 2.5-2.5 0-1-.588-1.85-1.438-2.25.27-.34.438-.78.438-1.25 0-1.1-.9-2-2-2h-5zm3 1h1c.55 0 1 .45 1 1s-.45 1-1 1h-1v-2zm0 3h1.5c.83 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5h-1.5v-3z'})); -export const iconBolt = () => icon(h('path', {d: 'M4 0l-3 5h2v3l3-5h-2v-3z'})); -export const iconBook = () => icon(h('path', {d: 'M1 0l-.188.031c-.39.08-.701.391-.781.781l-.031.188v5.5c0 .83.67 1.5 1.5 1.5h5.5v-1h-5.5c-.28 0-.5-.22-.5-.5s.22-.5.5-.5h5.5v-5.5c0-.28-.22-.5-.5-.5h-.5v3l-1-1-1 1v-3h-3z'})); -export const iconBookmark = () => icon(h('path', {d: 'M2 0v8l2-2 2 2v-8h-4z'})); -export const iconBox = () => icon(h('path', {d: 'M0 0v1h8v-1h-8zm0 2v5.906c0 .06.034.094.094.094h7.813c.06 0 .094-.034.094-.094v-5.906h-2.969v1.031h-2.031v-1.031h-3z'})); -export const iconBriefcase = () => icon(h('path', {d: 'M3 0c-.554 0-1 .458-1 1v1h-1.906c-.06 0-.094.034-.094.094v2.406c0 .28.22.5.5.5h7c.28 0 .5-.22.5-.5v-2.406c0-.06-.034-.094-.094-.094h-1.906v-1c0-.542-.446-1-1-1h-2zm0 1h2v1h-2v-1zm-3 4.906v2c0 .06.034.094.094.094h7.813c.06 0 .094-.034.094-.094v-2c-.16.05-.32.094-.5.094h-7c-.18 0-.34-.044-.5-.094z'})); -export const iconBrowser = () => icon(h('path', {d: 'M.344 0a.5.5 0 0 0-.344.5v7a.5.5 0 0 0 .5.5h7a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.5-.5h-7a.5.5 0 0 0-.094 0 .5.5 0 0 0-.063 0zm1.156 1c.28 0 .5.22.5.5s-.22.5-.5.5-.5-.22-.5-.5.22-.5.5-.5zm2 0h3c.28 0 .5.22.5.5s-.22.5-.5.5h-3c-.28 0-.5-.22-.5-.5s.22-.5.5-.5zm-2.5 2h6v4h-6v-4z'})); -export const iconBrush = () => icon(h('path', {d: 'M7.438.031l-.063.031-3.75 2.656-.125.156-.125.25c.719.229 1.271.781 1.5 1.5l.25-.125c.05-.02.126-.075.156-.125l2.656-3.75c.03-.04.04-.116 0-.156l-.406-.406-.094-.031zm-4.781 3.969c-.73 0-1.313.614-1.313 1.344 0 .99-.544 1.821-1.344 2.281.4.23.864.375 1.344.375 1.48 0 2.656-1.176 2.656-2.656 0-.73-.604-1.344-1.344-1.344z'})); -export const iconBug = () => icon(h('path', {d: 'M3.5 0c-1.19 0-1.978 1.69-1.188 2.5l-.281.219-1.313-.656a.5.5 0 0 0-.344-.063.5.5 0 0 0-.094.938l1.156.563c-.09.156-.186.328-.25.5h-.688a.5.5 0 0 0-.094 0 .502.502 0 1 0 .094 1h.5c0 .227.023.445.063.656l-.781.406a.5.5 0 1 0 .438.875l.656-.344c.245.46.59.844 1 1.094.35-.19.625-.439.625-.719v-1.438a.5.5 0 0 0 0-.094v-.813a.5.5 0 0 0 0-.219c.045-.231.254-.406.5-.406.28 0 .5.22.5.5v.875a.5.5 0 0 0 0 .094v.063a.5.5 0 0 0 0 .094v1.344c0 .27.275.497.625.688.41-.245.755-.604 1-1.063l.656.344a.5.5 0 1 0 .438-.875l-.781-.406c.04-.211.063-.429.063-.656h.5a.5.5 0 1 0 0-1h-.688c-.064-.172-.16-.344-.25-.5l1.156-.563a.5.5 0 0 0-.313-.938.5.5 0 0 0-.125.063l-1.313.656-.281-.219c.78-.83.003-2.5-1.188-2.5z'})); -export const iconBullhorn = () => icon(h('path', {d: 'M6.094 0l-.094.031v5.969h.907c.06 0 .094-.034.094-.094v-5.813c0-.06-.034-.094-.094-.094h-.813zm-1.094.5l-2.906 1.469-.188.031h-1.813c-.06 0-.094.034-.094.094v1.813c0 .06.034.094.094.094h.906l1.031 2.719c.11.25.406.36.656.25.25-.11.36-.406.25-.656l-.719-1.781c.033-.136.136-.25.281-.25v-.031l2.5 1.25v-5z'})); -export const iconCalculator = () => icon(h('path', {d: 'M.094 0c-.06 0-.094.034-.094.094v7.813c0 .06.034.094.094.094h6.813c.06 0 .094-.034.094-.094v-7.813c0-.06-.034-.094-.094-.094h-6.813zm.906 1h5v2h-5v-2zm0 3h1v1h-1v-1zm2 0h1v1h-1v-1zm2 0h1v3h-1v-3zm-4 2h1v1h-1v-1zm2 0h1v1h-1v-1z'})); -export const iconCalendar = () => icon(h('path', {d: 'M0 0v2h7v-2h-7zm0 3v4.906c0 .06.034.094.094.094h6.813c.06 0 .094-.034.094-.094v-4.906h-7zm1 1h1v1h-1v-1zm2 0h1v1h-1v-1zm2 0h1v1h-1v-1zm-4 2h1v1h-1v-1zm2 0h1v1h-1v-1z'})); -export const iconCameraSlr = () => icon(h('path', {d: 'M4.094 0c-.06 0-.105.044-.125.094l-.938 1.813c-.02.05-.065.094-.125.094h-1.406c-.83 0-1.5.67-1.5 1.5v4.406c0 .06.034.094.094.094h7.813c.06 0 .094-.034.094-.094v-5.813c0-.06-.034-.094-.094-.094h-.813c-.06 0-.105-.044-.125-.094l-.938-1.813c-.02-.05-.065-.094-.125-.094h-1.813zm-2.594 3c.28 0 .5.22.5.5s-.22.5-.5.5-.5-.22-.5-.5.22-.5.5-.5zm3.5 0c1.1 0 2 .9 2 2s-.9 2-2 2-2-.9-2-2 .9-2 2-2zm0 1c-.55 0-1 .45-1 1s.45 1 1 1 1-.45 1-1-.45-1-1-1z'})); -export const iconCaretBottom = () => icon(h('path', {d: 'M0 2l4 4 4-4h-8z'})); -export const iconCaretLeft = () => icon(h('path', {d: 'M6 0l-4 4 4 4v-8z'})); -export const iconCaretRight = () => icon(h('path', {d: 'M2 0v8l4-4-4-4z'})); -export const iconCaretTop = () => icon(h('path', {d: 'M4 2l-4 4h8l-4-4z'})); -export const iconChat = () => icon(h('path', {d: 'M0 0v5l1-1h1v-3h3v-1h-5zm3 2v4h4l1 1v-5h-5z'})); -export const iconCheck = () => icon(h('path', {d: 'M6.406 1l-.719.688-2.781 2.781-.781-.781-.719-.688-1.406 1.406.688.719 1.5 1.5.719.688.719-.688 3.5-3.5.688-.719-1.406-1.406z'})); -export const iconChevronBottom = () => icon(h('path', {d: 'M1.5 1l-1.5 1.5 4 4 4-4-1.5-1.5-2.5 2.5-2.5-2.5z'})); -export const iconChevronLeft = () => icon(h('path', {d: 'M5 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'})); -export const iconChevronRight = () => icon(h('path', {d: 'M2.5 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'})); -export const iconChevronTop = () => icon(h('path', {d: 'M4 1l-4 4 1.5 1.5 2.5-2.5 2.5 2.5 1.5-1.5-4-4z'})); -export const iconCircleCheck = () => icon(h('path', {d: 'M4 0c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm2 1.781l.719.719-3.219 3.219-1.719-1.719.719-.719 1 1 2.5-2.5z'})); -export const iconCircleX = () => icon(h('path', {d: 'M4 0c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm-1.5 1.781l1.5 1.5 1.5-1.5.719.719-1.5 1.5 1.5 1.5-.719.719-1.5-1.5-1.5 1.5-.719-.719 1.5-1.5-1.5-1.5.719-.719z'})); -export const iconClipboard = () => icon(h('path', {d: 'M3.5 0c-.28 0-.5.22-.5.5v.5h-.75c-.14 0-.25.11-.25.25v.75h3v-.75c0-.14-.11-.25-.25-.25h-.75v-.5c0-.28-.22-.5-.5-.5zm-3.25 1c-.14 0-.25.11-.25.25v6.5c0 .14.11.25.25.25h6.5c.14 0 .25-.11.25-.25v-6.5c0-.14-.11-.25-.25-.25h-.75v2h-5v-2h-.75z'})); -export const iconClock = () => icon(h('path', {d: 'M4 0c-2.203 0-4 1.797-4 4 0 2.203 1.797 4 4 4 2.203 0 4-1.797 4-4 0-2.203-1.797-4-4-4zm0 1c1.663 0 3 1.337 3 3s-1.337 3-3 3-3-1.337-3-3 1.337-3 3-3zm-.5 1v2.219l.156.125.5.5.344.375.719-.719-.375-.344-.344-.344v-1.813h-1z'})); -export const iconCloudDownload = () => icon(h('path', {d: 'M4.5 0c-1.21 0-2.27.86-2.5 2-1.1 0-2 .9-2 2 0 .37.111.7.281 1h2.719v-.5c0-.83.67-1.5 1.5-1.5s1.5.67 1.5 1.5v.5h1.906c.05-.16.094-.32.094-.5 0-.65-.42-1.29-1-1.5v-.5c0-1.38-1.12-2.5-2.5-2.5zm-.156 4a.5.5 0 0 0-.344.5v1.5h-1.5l2 2 2-2h-1.5v-1.5a.5.5 0 0 0-.594-.5.5.5 0 0 0-.063 0z'})); -export const iconCloudUpload = () => icon(h('path', {d: 'M4.5 0c-1.21 0-2.27.86-2.5 2-1.1 0-2 .9-2 2 0 .37.111.7.281 1h2.219l2-2 2 2h1.406c.05-.16.094-.32.094-.5 0-.65-.42-1.29-1-1.5v-.5c0-1.38-1.12-2.5-2.5-2.5zm0 4.5l-2.5 2.5h2v.5a.5.5 0 1 0 1 0v-.5h2l-2.5-2.5z'})); -export const iconCloud = () => icon(h('path', {d: 'M4.5 1c-1.21 0-2.27.86-2.5 2-1.1 0-2 .9-2 2s.9 2 2 2h4.5c.83 0 1.5-.67 1.5-1.5 0-.65-.42-1.29-1-1.5v-.5c0-1.38-1.12-2.5-2.5-2.5z'})); -export const iconCode = () => icon(h('path', {d: 'M5 1l-3 6h1l3-6h-1zm-4 1l-1 2 1 2h1l-1-2 1-2h-1zm5 0l1 2-1 2h1l1-2-1-2h-1z'})); -export const iconCog = () => icon(h('path', {d: 'M3.5 0l-.5 1.188-.281.125-1.188-.5-.719.719.5 1.188-.125.281-1.188.5v1l1.188.5.125.313-.5 1.156.719.719 1.188-.5.281.125.5 1.188h1l.5-1.188.281-.125 1.188.5.719-.719-.5-1.188.125-.281 1.188-.5v-1l-1.188-.5-.125-.281.469-1.188-.688-.719-1.188.5-.281-.125-.5-1.188h-1zm.5 2.5c.83 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5-1.5-.67-1.5-1.5.67-1.5 1.5-1.5z'})); -export const iconCollapseDown = () => icon(h('path', {d: 'M0 0v2h8v-2h-8zm2 3l2 2 2-2h-4zm-2 4v1h8v-1h-8z'})); -export const iconCollapseLeft = () => icon(h('path', {d: 'M0 0v8h1v-8h-1zm6 0v8h2v-8h-2zm-1 2l-2 2 2 2v-4z'})); -export const iconCollapseRight = () => icon(h('path', {d: 'M0 0v8h2v-8h-2zm7 0v8h1v-8h-1zm-4 2v4l2-2-2-2z'})); -export const iconCollapseUp = () => icon(h('path', {d: 'M0 0v1h8v-1h-8zm4 3l-2 2h4l-2-2zm-4 3v2h8v-2h-8z'})); -export const iconCommand = () => icon(h('path', {d: 'M1.5 0c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5h.5v1h-.5c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5v-.5h1v.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5-.67-1.5-1.5-1.5h-.5v-1h.5c.83 0 1.5-.67 1.5-1.5s-.67-1.5-1.5-1.5-1.5.67-1.5 1.5v.5h-1v-.5c0-.83-.67-1.5-1.5-1.5zm0 1c.28 0 .5.22.5.5v.5h-.5c-.28 0-.5-.22-.5-.5s.22-.5.5-.5zm4 0c.28 0 .5.22.5.5s-.22.5-.5.5h-.5v-.5c0-.28.22-.5.5-.5zm-2.5 2h1v1h-1v-1zm-1.5 2h.5v.5c0 .28-.22.5-.5.5s-.5-.22-.5-.5.22-.5.5-.5zm3.5 0h.5c.28 0 .5.22.5.5s-.22.5-.5.5-.5-.22-.5-.5v-.5z'})); -export const iconCommentSquare = () => icon(h('path', {d: 'M.094 0c-.06 0-.094.034-.094.094v5.813c0 .06.034.094.094.094h5.906l2 2v-7.906c0-.06-.034-.094-.094-.094h-7.813z'})); -export const iconCompass = () => icon(h('path', {d: 'M4 0c-2.203 0-4 1.797-4 4 0 2.203 1.797 4 4 4 2.203 0 4-1.797 4-4 0-2.203-1.797-4-4-4zm0 1c1.663 0 3 1.337 3 3s-1.337 3-3 3-3-1.337-3-3 1.337-3 3-3zm2 1l-3 1-1 3 3-1 1-3zm-2 1.5c.28 0 .5.22.5.5s-.22.5-.5.5-.5-.22-.5-.5.22-.5.5-.5z'})); -export const iconContrast = () => icon(h('path', {d: 'M4 0c-2.203 0-4 1.797-4 4 0 2.203 1.797 4 4 4 2.203 0 4-1.797 4-4 0-2.203-1.797-4-4-4zm0 1c1.663 0 3 1.337 3 3s-1.337 3-3 3v-6z'})); -export const iconCopywriting = () => icon(h('path', {d: 'M0 0v1h8v-1h-8zm0 2v1h5v-1h-5zm0 3v1h8v-1h-8zm0 2v1h6v-1h-6zm7.5 0c-.276 0-.5.224-.5.5s.224.5.5.5.5-.224.5-.5-.224-.5-.5-.5z'})); -export const iconCreditCard = () => icon(h('path', {d: 'M.25 1c-.14 0-.25.11-.25.25v.75h8v-.75c0-.14-.11-.25-.25-.25h-7.5zm-.25 2v3.75c0 .14.11.25.25.25h7.5c.14 0 .25-.11.25-.25v-3.75h-8zm1 2h1v1h-1v-1zm2 0h1v1h-1v-1z'})); -export const iconCrop = () => icon(h('path', {d: 'M1 0v1h-1v1h1v5h5v1h1v-1h1v-1h-1v-4.5l1-1-.5-.5-1 1h-4.5v-1h-1zm1 2h3.5l-3.5 3.5v-3.5zm4 .5v3.5h-3.5l3.5-3.5z'})); -export const iconDashboard = () => icon(h('path', {d: 'M4 0c-2.203 0-4 1.797-4 4 0 2.203 1.797 4 4 4 2.203 0 4-1.797 4-4 0-2.203-1.797-4-4-4zm0 1c1.663 0 3 1.337 3 3s-1.337 3-3 3-3-1.337-3-3 1.337-3 3-3zm0 1c-.276 0-.5.224-.5.5s.224.5.5.5.5-.224.5-.5-.224-.5-.5-.5zm-1.656 1a.5.5 0 0 0-.188.844l.906.906-.063.25c0 .552.448 1 1 1s1-.448 1-1-.448-1-1-1l-.25.063-.906-.906a.5.5 0 0 0-.438-.156.5.5 0 0 0-.063 0zm3.156 0c-.276 0-.5.224-.5.5s.224.5.5.5.5-.224.5-.5-.224-.5-.5-.5z'})); -export const iconDataTransferDownload = () => icon(h('path', {d: 'M3 0v3h-2l3 3 3-3h-2v-3h-2zm-3 7v1h8v-1h-8z'})); -export const iconDataTransferUpload = () => icon(h('path', {d: 'M0 0v1h8v-1h-8zm4 2l-3 3h2v3h2v-3h2l-3-3z'})); -export const iconDelete = () => icon(h('path', {d: 'M2 1l-2 3 2 3h6v-6h-6zm1.5.781l1.5 1.5 1.5-1.5.719.719-1.5 1.5 1.5 1.5-.719.719-1.5-1.5-1.5 1.5-.719-.719 1.5-1.5-1.5-1.5.719-.719z'})); -export const iconDial = () => icon(h('path', {d: 'M4 1c-2.201 0-4 1.799-4 4h1c0-1.659 1.341-3 3-3s3 1.341 3 3h1c0-2.201-1.799-4-4-4zm-.594 2.094c-.82.25-1.406 1.006-1.406 1.906 0 1.1.9 2 2 2s2-.9 2-2c0-.9-.586-1.656-1.406-1.906l-.594.875-.594-.875z'})); -export const iconDocument = () => icon(h('path', {d: 'M0 0v8h7v-4h-4v-4h-3zm4 0v3h3l-3-3zm-3 2h1v1h-1v-1zm0 2h1v1h-1v-1zm0 2h4v1h-4v-1z'})); -export const iconDoubleQuoteSansLeft = () => icon(h('path', {d: 'M0 1v6l3-3v-3h-3zm5 0v6l3-3v-3h-3z'})); -export const iconDoubleQuoteSansRight = () => icon(h('path', {d: 'M3 1l-3 3v3h3v-6zm5 0l-3 3v3h3v-6z'})); -export const iconDoubleQuoteSerifLeft = () => icon(h('path', {d: 'M3 1c-1.651 0-3 1.349-3 3v3h3v-3h-2c0-1.109.891-2 2-2v-1zm5 0c-1.651 0-3 1.349-3 3v3h3v-3h-2c0-1.109.891-2 2-2v-1z'})); -export const iconDoubleQuoteSerifRight = () => icon(h('path', {d: 'M0 1v3h2c0 1.109-.891 2-2 2v1c1.651 0 3-1.349 3-3v-3h-3zm5 0v3h2c0 1.109-.891 2-2 2v1c1.651 0 3-1.349 3-3v-3h-3z'})); -export const iconDroplet = () => icon(h('path', {d: 'M4 0l-.344.344c-.11.11-2.656 2.685-2.656 4.875 0 1.65 1.35 3 3 3s3-1.35 3-3c0-2.19-2.546-4.765-2.656-4.875l-.344-.344zm-1.5 4.719c.28 0 .5.22.5.5 0 .55.45 1 1 1 .28 0 .5.22.5.5s-.22.5-.5.5c-1.1 0-2-.9-2-2 0-.28.22-.5.5-.5z'})); -export const iconEject = () => icon(h('path', {d: 'M4 0l-4 5h8l-4-5zm-4 6v2h8v-2h-8z'})); -export const iconElevator = () => icon(h('path', {d: 'M4 0l-3 3h6l-3-3zm-3 5l3 3 3-3h-6z'})); -export const iconEllipses = () => icon(h('path', {d: 'M0 3v2h2v-2h-2zm3 0v2h2v-2h-2zm3 0v2h2v-2h-2z'})); -export const iconEnvelopeClosed = () => icon(h('path', {d: 'M0 1v1l4 2 4-2v-1h-8zm0 2v4h8v-4l-4 2-4-2z'})); -export const iconEnvelopeOpen = () => icon(h('path', {d: 'M4 0l-4 2v6h8v-6l-4-2zm0 1.125l3 1.5v1.875l-3 1.5-3-1.5v-1.875l3-1.5zm-2 1.875v1l2 1 2-1v-1h-4z'})); -export const iconExcerpt = () => icon(h('path', {d: 'M0 0v1h7v-1h-7zm0 2v1h5v-1h-5zm0 2v1h8v-1h-8zm0 2v1h1v-1h-1zm2 0v1h1v-1h-1zm2 0v1h1v-1h-1z'})); -export const iconExpandDown = () => icon(h('path', {d: 'M0 0v1h8v-1h-8zm2 2l2 2 2-2h-4zm-2 4v2h8v-2h-8z'})); -export const iconExpandLeft = () => icon(h('path', {d: 'M0 0v8h1v-8h-1zm6 0v8h2v-8h-2zm-4 2v4l2-2-2-2z'})); -export const iconExpandRight = () => icon(h('path', {d: 'M0 0v8h2v-8h-2zm7 0v8h1v-8h-1zm-1 2l-2 2 2 2v-4z'})); -export const iconExpandUp = () => icon(h('path', {d: 'M0 0v2h8v-2h-8zm4 4l-2 2h4l-2-2zm-4 3v1h8v-1h-8z'})); -export const iconExternalLink = () => icon(h('path', {d: 'M0 0v8h8v-2h-1v1h-6v-6h1v-1h-2zm4 0l1.5 1.5-2.5 2.5 1 1 2.5-2.5 1.5 1.5v-4h-4z'})); -export const iconEye = () => icon(h('path', {d: 'M4.031 1c-2.53 0-4.031 3-4.031 3s1.501 3 4.031 3c2.47 0 3.969-3 3.969-3s-1.499-3-3.969-3zm-.031 1c1.1 0 2 .9 2 2s-.9 2-2 2-2-.9-2-2 .9-2 2-2zm0 1c-.55 0-1 .45-1 1s.45 1 1 1 1-.45 1-1c0-.1-.032-.191-.063-.281-.08.16-.237.281-.438.281-.28 0-.5-.22-.5-.5 0-.2.121-.357.281-.438-.09-.03-.181-.063-.281-.063z'})); -export const iconEyedropper = () => icon(h('path', {d: 'M3.313 0a.5.5 0 0 0-.188.844l.625.625-3.594 3.656-.156.156v2.719h2.719l.125-.156 3.656-3.656.625.656a.5.5 0 1 0 .719-.688l-.938-.938.656-.656c.59-.58.59-1.545 0-2.125-.56-.57-1.555-.57-2.125 0l-.656.656-.938-.938a.5.5 0 0 0-.469-.156.5.5 0 0 0-.063 0zm1.156 2.188l1.313 1.313-3.156 3.156-1.281-1.313 3.125-3.156z'})); -export const iconFile = () => icon(h('path', {d: 'M0 0v8h7v-4h-4v-4h-3zm4 0v3h3l-3-3z'})); -export const iconFire = () => icon(h('path', {d: 'M2 0c1 2-2 3-2 5l2 3c-.98-1.98 2-3 2-5l-2-3zm3 3c1 2-2 3-2 5h3c.4 0 1-.5 1-2 0-2-2-3-2-3z'})); -export const iconFlag = () => icon(h('path', {d: 'M0 0v8h1v-8h-1zm2 0v4h2v1h4l-2-1.969 2-2.031h-3v-1h-3z'})); -export const iconFlash = () => icon(h('path', {d: 'M3.5 0l-1.5 3h2l-.656 2h-1.344l1 3 3-3h-1.5l1.5-3h-2l1-2h-1.5z'})); -export const iconFolder = () => icon(h('path', {d: 'M0 0v2h8v-1h-5v-1h-3zm0 3v4.5c0 .28.22.5.5.5h7c.28 0 .5-.22.5-.5v-4.5h-8z'})); -export const iconFork = () => icon(h('path', {d: 'M1.5 0c-.828 0-1.5.672-1.5 1.5 0 .656.414 1.202 1 1.406v2.188c-.586.204-1 .75-1 1.406 0 .828.672 1.5 1.5 1.5s1.5-.672 1.5-1.5c0-.595-.341-1.101-.844-1.344.09-.09.205-.156.344-.156h2c.823 0 1.5-.677 1.5-1.5v-.594c.586-.204 1-.75 1-1.406 0-.828-.672-1.5-1.5-1.5s-1.5.672-1.5 1.5c0 .656.414 1.202 1 1.406v.594c0 .277-.223.5-.5.5h-2c-.171 0-.346.04-.5.094v-1.188c.586-.204 1-.75 1-1.406 0-.828-.672-1.5-1.5-1.5z'})); -export const iconFullscreenEnter = () => icon(h('path', {d: 'M0 0v4l1.5-1.5 1.5 1.5 1-1-1.5-1.5 1.5-1.5h-4zm5 4l-1 1 1.5 1.5-1.5 1.5h4v-4l-1.5 1.5-1.5-1.5z'})); -export const iconFullscreenExit = () => icon(h('path', {d: 'M1 0l-1 1 1.5 1.5-1.5 1.5h4v-4l-1.5 1.5-1.5-1.5zm3 4v4l1.5-1.5 1.5 1.5 1-1-1.5-1.5 1.5-1.5h-4z'})); -export const iconGlobe = () => icon(h('path', {d: 'M4 0c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm0 1c.333 0 .637.086.938.188-.214.197-.45.383-.406.563.04.18.688.13.688.5 0 .27-.425.346-.125.656.35.35-.636.978-.656 1.438-.03.83.841.969 1.531.969.424 0 .503.195.469.438-.546.758-1.438 1.25-2.438 1.25-.378 0-.729-.09-1.063-.219.224-.442-.313-1.344-.781-1.625-.226-.226-.689-.114-.969-.219-.092-.271-.178-.545-.188-.844.031-.05.081-.094.156-.094.19 0 .454.374.594.344.18-.04-.742-1.313-.313-1.563.2-.12.609.394.469-.156-.12-.51.366-.276.656-.406.26-.11.455-.414.125-.594l-.219-.188c.45-.27.972-.438 1.531-.438zm2.313 1.094c.184.222.323.481.438.75l-.188.219c-.29.27-.327-.212-.438-.313-.13-.11-.638.025-.688-.125-.077-.181.499-.418.875-.531z'})); -export const iconGraph = () => icon(h('path', {d: 'M7.031 0l-3.031 3-1-1-3 3.031 1 1 2-2.031 1 1 4-4-.969-1zm-7.031 7v1h8v-1h-8z'})); -export const iconGridFourUp = () => icon(h('path', {d: 'M0 0v1h1v-1h-1zm2 0v1h1v-1h-1zm2 0v1h1v-1h-1zm2 0v1h1v-1h-1zm-6 2v1h1v-1h-1zm2 0v1h1v-1h-1zm2 0v1h1v-1h-1zm2 0v1h1v-1h-1zm-6 2v1h1v-1h-1zm2 0v1h1v-1h-1zm2 0v1h1v-1h-1zm2 0v1h1v-1h-1zm-6 2v1h1v-1h-1zm2 0v1h1v-1h-1zm2 0v1h1v-1h-1zm2 0v1h1v-1h-1z'})); -export const iconGridThreeUp = () => icon(h('path', {d: 'M0 0v2h2v-2h-2zm3 0v2h2v-2h-2zm3 0v2h2v-2h-2zm-6 3v2h2v-2h-2zm3 0v2h2v-2h-2zm3 0v2h2v-2h-2zm-6 3v2h2v-2h-2zm3 0v2h2v-2h-2zm3 0v2h2v-2h-2z'})); -export const iconGridTwoUp = () => icon(h('path', {d: 'M0 0v3h3v-3h-3zm5 0v3h3v-3h-3zm-5 5v3h3v-3h-3zm5 0v3h3v-3h-3z'})); -export const iconHardDrive = () => icon(h('path', {d: 'M.188 0c-.11 0-.188.077-.188.188v3.313c0 .28.22.5.5.5h6c.28 0 .5-.22.5-.5v-3.313c0-.11-.077-.188-.188-.188h-6.625zm-.188 4.906v2.906c0 .11.077.188.188.188h6.625c.11 0 .188-.077.188-.188v-2.906c-.16.05-.32.094-.5.094h-6c-.18 0-.34-.044-.5-.094zm5.5 1.094c.28 0 .5.22.5.5s-.22.5-.5.5-.5-.22-.5-.5.22-.5.5-.5z'})); -export const iconHeader = () => icon(h('path', {d: 'M0 0v1h.5c.28 0 .5.22.5.5v4c0 .28-.22.5-.5.5h-.5v1h3v-1h-.5c-.28 0-.5-.22-.5-.5v-1.5h3v1.5c0 .28-.22.5-.5.5h-.5v1h3v-1h-.5c-.28 0-.5-.22-.5-.5v-4c0-.28.22-.5.5-.5h.5v-1h-3v1h.5c.28 0 .5.22.5.5v1.5h-3v-1.5c0-.28.22-.5.5-.5h.5v-1h-3z'})); -export const iconHeadphones = () => icon(h('path', {d: 'M4 0c-1.651 0-3 1.349-3 3v1h-.5a.5.5 0 0 0-.5.5v2a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-3.5c0-1.109.891-2 2-2s2 .891 2 2v3.5a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-2a.5.5 0 0 0-.5-.5h-.5v-1c0-1.651-1.349-3-3-3z'})); -export const iconHeart = () => icon(h('path', {d: 'M2 1c-.55 0-1.046.224-1.406.594-.37.36-.594.856-.594 1.406 0 .55.224 1.046.594 1.406l3.406 3.438 3.406-3.438c.37-.37.594-.856.594-1.406 0-.55-.224-1.046-.594-1.406-.36-.37-.856-.594-1.406-.594-.55 0-1.046.224-1.406.594-.37.36-.594.856-.594 1.406 0-.55-.224-1.046-.594-1.406-.36-.37-.856-.594-1.406-.594z'})); -export const iconHome = () => icon(h('path', {d: 'M4 0l-4 3h1v4h2v-2h2v2h2v-4.031l1 .031-4-3z'})); -export const imagE = () => icon(h('path', {d: 'M0 0v8h8v-8h-8zm1 1h6v3l-1-1-1 1 2 2v1h-1l-4-4-1 1v-3z'})); -export const inboX = () => icon(h('path', {d: 'M.188 0c-.11 0-.188.077-.188.188v7.625c0 .11.077.188.188.188h7.625c.11 0 .188-.077.188-.188v-7.625c0-.11-.077-.188-.188-.188h-7.625zm.813 2h6v3h-1l-1 1h-2l-1-1h-1v-3z'})); -export const infiNity = () => icon(h('path', {d: 'M2 2c-1.31 0-2 1.01-2 2s.69 2 2 2c.79 0 1.42-.559 2-1.219.58.66 1.19 1.219 2 1.219 1.31 0 2-1.01 2-2s-.69-2-2-2c-.81 0-1.42.559-2 1.219-.57-.66-1.21-1.219-2-1.219zm0 1c.42 0 .884.47 1.344 1-.46.53-.924 1-1.344 1-.74 0-1-.54-1-1 0-.46.26-1 1-1zm4 0c.74 0 1 .54 1 1 0 .46-.26 1-1 1-.43 0-.894-.47-1.344-1 .45-.53.914-1 1.344-1z'})); -export const info = () => icon(h('path', {d: 'M5 0c-.552 0-1 .448-1 1s.448 1 1 1 1-.448 1-1-.448-1-1-1zm-1.5 2.5c-.83 0-1.5.67-1.5 1.5h1c0-.28.22-.5.5-.5s.5.22.5.5-1 1.64-1 2.5c0 .86.67 1.5 1.5 1.5s1.5-.67 1.5-1.5h-1c0 .28-.22.5-.5.5s-.5-.22-.5-.5c0-.36 1-1.84 1-2.5 0-.81-.67-1.5-1.5-1.5z'})); -export const italIc = () => icon(h('path', {d: 'M2 0v1h1.625l-.063.125-2 5-.344.875h-1.219v1h5v-1h-1.625l.063-.125 2-5 .344-.875h1.219v-1h-5z'})); -export const iconJustifyCenter = () => icon(h('path', {d: 'M0 0v1h8v-1h-8zm0 2v1h8v-1h-8zm0 2v1h8v-1h-8zm1 2v1h6v-1h-6z'})); -export const iconJustifyLeft = () => icon(h('path', {d: 'M0 0v1h8v-1h-8zm0 2v1h8v-1h-8zm0 2v1h8v-1h-8zm0 2v1h6v-1h-6z'})); -export const iconJustifyRight = () => icon(h('path', {d: 'M0 0v1h8v-1h-8zm0 2v1h8v-1h-8zm0 2v1h8v-1h-8zm2 2v1h6v-1h-6z'})); -export const iconKey = () => icon(h('path', {d: 'M5.5 0c-1.38 0-2.5 1.12-2.5 2.5 0 .16.033.297.063.438l-3.063 3.063v2h3v-2h2v-1l.063-.063c.14.03.277.063.438.063 1.38 0 2.5-1.12 2.5-2.5s-1.12-2.5-2.5-2.5zm.5 1c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1z'})); -export const iconLaptop = () => icon(h('path', {d: 'M1.344 0a.5.5 0 0 0-.344.5v3.5h-1v1.5c0 .28.22.5.5.5h7c.28 0 .5-.22.5-.5v-1.5h-1v-3.5a.5.5 0 0 0-.5-.5h-5a.5.5 0 0 0-.094 0 .5.5 0 0 0-.063 0zm.656 1h4v3h-1v1h-2v-1h-1v-3z'})); -export const iconLayers = () => icon(h('path', {d: 'M0 0v4h4v-4h-4zm5 2v3h-3v1h4v-4h-1zm2 2v3h-3v1h4v-4h-1z'})); -export const iconLinkBroken = () => icon(h('path', {d: 'M2 0v1h-1v1h2v-2h-1zm3.875.031c-.184.01-.354.03-.531.094-.27.095-.531.25-.75.469l-.438.438a.5.5 0 1 0 .688.688l.438-.438c.101-.101.245-.173.375-.219.352-.126.78-.064 1.063.219.395.389.4 1.037 0 1.438l-1.5 1.5a.5.5 0 1 0 .688.688l1.5-1.5c.78-.78.785-2.041 0-2.813-.279-.279-.606-.452-.969-.531-.181-.039-.379-.041-.563-.031zm-3.594 2.906a.5.5 0 0 0-.188.156l-1.5 1.5c-.78.78-.785 2.041 0 2.813.557.557 1.355.722 2.063.469.27-.095.531-.25.75-.469l.438-.438a.5.5 0 1 0-.688-.688l-.438.438c-.101.101-.245.173-.375.219-.352.126-.78.064-1.063-.219-.395-.389-.4-1.037 0-1.438l1.5-1.5a.5.5 0 0 0-.438-.844.5.5 0 0 0-.063 0zm2.719 3.063v2h1v-1h1v-1h-2z'})); -export const iconLinkIntact = () => icon(h('path', {d: 'M5.875.031c-.184.01-.354.03-.531.094-.27.095-.531.25-.75.469a.5.5 0 1 0 .688.688c.101-.101.245-.173.375-.219.352-.126.78-.064 1.063.219.395.389.4 1.037 0 1.438l-1.5 1.5c-.434.434-.799.483-1.063.469-.264-.015-.406-.125-.406-.125a.504.504 0 1 0-.5.875s.34.222.844.25c.504.028 1.197-.165 1.813-.781l1.5-1.5c.78-.78.785-2.041 0-2.813-.279-.279-.606-.452-.969-.531-.181-.039-.379-.041-.563-.031zm-2 2.313c-.501-.019-1.186.155-1.781.75l-1.5 1.5c-.78.78-.785 2.041 0 2.813.557.557 1.355.722 2.063.469.27-.095.531-.25.75-.469a.5.5 0 1 0-.688-.688c-.101.101-.245.173-.375.219-.352.126-.78.064-1.063-.219-.395-.389-.4-1.037 0-1.438l1.5-1.5c.405-.405.752-.448 1.031-.438.279.011.469.094.469.094a.5.5 0 1 0 .438-.875s-.343-.199-.844-.219z'})); -export const iconListRich = () => icon(h('path', {d: 'M0 0v3h3v-3h-3zm4 0v1h4v-1h-4zm0 2v1h3v-1h-3zm-4 2v3h3v-3h-3zm4 0v1h4v-1h-4zm0 2v1h3v-1h-3z'})); -export const iconList = () => icon(h('path', {d: 'M.5 0c-.276 0-.5.224-.5.5s.224.5.5.5.5-.224.5-.5-.224-.5-.5-.5zm1.5 0v1h6v-1h-6zm-1.5 2c-.276 0-.5.224-.5.5s.224.5.5.5.5-.224.5-.5-.224-.5-.5-.5zm1.5 0v1h6v-1h-6zm-1.5 2c-.276 0-.5.224-.5.5s.224.5.5.5.5-.224.5-.5-.224-.5-.5-.5zm1.5 0v1h6v-1h-6zm-1.5 2c-.276 0-.5.224-.5.5s.224.5.5.5.5-.224.5-.5-.224-.5-.5-.5zm1.5 0v1h6v-1h-6z'})); -export const iconLocation = () => icon(h('path', {d: 'M8 0l-8 4 3 1 1 3 4-8z'})); -export const iconLockLocked = (className) => icon(h('path', {d: 'M4 0c-1.099 0-2 .901-2 2v1h-1v4h6v-4h-1v-1c0-1.099-.901-2-2-2zm0 1c.561 0 1 .439 1 1v1h-2v-1c0-.561.439-1 1-1z'}), className); -export const iconLockUnlocked = () => icon(h('path', {d: 'M4 0c-1.099 0-2 .901-2 2h1c0-.561.439-1 1-1 .561 0 1 .439 1 1v2h-4v4h6v-4h-1v-2c0-1.099-.901-2-2-2z'})); -export const iconLoopCircular = () => icon(h('path', {d: 'M4 1c-1.651 0-3 1.349-3 3h-1l1.5 2 1.5-2h-1c0-1.109.891-2 2-2v-1zm2.5 1l-1.5 2h1c0 1.109-.891 2-2 2v1c1.651 0 3-1.349 3-3h1l-1.5-2z'})); -export const iconLoopSquare = () => icon(h('path', {d: 'M1 0v2h1v-1h4v2h-1l1.5 2.5 1.5-2.5h-1v-3h-6zm.5 2.5l-1.5 2.5h1v3h6v-2h-1v1h-4v-2h1l-1.5-2.5z'})); -export const iconLoop = () => icon(h('path', {d: 'M6 0v1h-5c-.554 0-1 .446-1 1v1h1v-1h5v1l2-1.5-2-1.5zm-4 4l-2 1.5 2 1.5v-1h5c.542 0 1-.458 1-1v-1h-1v1h-5v-1z'})); -export const iconMagnifyingGlass = () => icon(h('path', {d: 'M3.5 0c-1.927 0-3.5 1.573-3.5 3.5s1.573 3.5 3.5 3.5c.592 0 1.166-.145 1.656-.406a1 1 0 0 0 .125.125l1 1a1.016 1.016 0 1 0 1.438-1.438l-1-1a1 1 0 0 0-.156-.125c.266-.493.438-1.059.438-1.656 0-1.927-1.573-3.5-3.5-3.5zm0 1c1.387 0 2.5 1.113 2.5 2.5 0 .661-.241 1.273-.656 1.719l-.031.031a1 1 0 0 0-.125.125c-.442.397-1.043.625-1.688.625-1.387 0-2.5-1.113-2.5-2.5s1.113-2.5 2.5-2.5z'})); -export const iconMapMarker = () => icon(h('path', {d: 'M4 0c-1.66 0-3 1.34-3 3 0 2 3 5 3 5s3-3 3-5c0-1.66-1.34-3-3-3zm0 1c1.1 0 2 .9 2 2s-.9 2-2 2-2-.9-2-2 .9-2 2-2z'})); -export const iconMap = () => icon(h('path', {d: 'M0 0v8h8v-2.375a.5.5 0 0 0 0-.219v-5.406h-8zm1 1h6v4h-1.5a.5.5 0 0 0-.094 0 .502.502 0 1 0 .094 1h1.5v1h-6v-6zm2.5 1c-.83 0-1.5.67-1.5 1.5 0 1 1.5 2.5 1.5 2.5s1.5-1.5 1.5-2.5c0-.83-.67-1.5-1.5-1.5zm0 1c.28 0 .5.22.5.5s-.22.5-.5.5-.5-.22-.5-.5.22-.5.5-.5z'})); -export const iconMediaPause = () => icon(h('path', {d: 'M1 1v6h2v-6h-2zm4 0v6h2v-6h-2z'})); -export const iconMediaPlay = () => icon(h('path', {d: 'M1 1v6l6-3-6-3z'})); -export const iconMediaRecord = () => icon(h('path', {d: 'M4 1c-1.657 0-3 1.343-3 3s1.343 3 3 3 3-1.343 3-3-1.343-3-3-3z'})); -export const iconMediaSkipBackward = () => icon(h('path', {d: 'M4 1l-4 3 4 3v-6zm0 3l4 3v-6l-4 3z'})); -export const iconMediaSkipForward = () => icon(h('path', {d: 'M0 1v6l4-3-4-3zm4 3v3l4-3-4-3v3z'})); -export const iconMediaStepBackward = () => icon(h('path', {d: 'M0 1v6h2v-6h-2zm2 3l5 3v-6l-5 3z'})); -export const iconMediaStepForward = () => icon(h('path', {d: 'M0 1v6l5-3-5-3zm5 3v3h2v-6h-2v3z'})); -export const iconMediaStop = () => icon(h('path', {d: 'M1 1v6h6v-6h-6z'})); -export const iconMedicalCross = () => icon(h('path', {d: 'M2 0v2h-2v4h2v2h4v-2h2v-4h-2v-2h-4z'})); -export const iconMenu = () => icon(h('path', {d: 'M0 1v1h8v-1h-8zm0 2.969v1h8v-1h-8zm0 3v1h8v-1h-8z'})); -export const iconMicrophone = () => icon(h('path', {d: 'M2.906-.031a1 1 0 0 0-.125.031 1 1 0 0 0-.781 1v2a1 1 0 1 0 2 0v-2a1 1 0 0 0-1.094-1.031zm-2.563 2.031a.5.5 0 0 0-.344.5v.5c0 1.476 1.091 2.693 2.5 2.938v1.063h-.5c-.55 0-1 .45-1 1h4c0-.55-.45-1-1-1h-.5v-1.063c1.409-.244 2.5-1.461 2.5-2.938v-.5a.5.5 0 1 0-1 0v.5c0 1.109-.891 2-2 2s-2-.891-2-2v-.5a.5.5 0 0 0-.594-.5.5.5 0 0 0-.063 0z'})); -export const iconMinus = () => icon(h('path', {d: 'M0 3v2h8v-2h-8z'})); -export const iconMonitor = () => icon(h('path', {d: 'M.344 0a.5.5 0 0 0-.344.5v5a.5.5 0 0 0 .5.5h2.5v1h-1c-.55 0-1 .45-1 1h6c0-.55-.45-1-1-1h-1v-1h2.5a.5.5 0 0 0 .5-.5v-5a.5.5 0 0 0-.5-.5h-7a.5.5 0 0 0-.094 0 .5.5 0 0 0-.063 0zm.656 1h6v4h-6v-4z'})); -export const iconMoon = () => icon(h('path', {d: 'M2.719 0c-1.58.53-2.719 2.021-2.719 3.781 0 2.21 1.79 4 4 4 1.76 0 3.251-1.17 3.781-2.75-.4.14-.831.25-1.281.25-2.21 0-4-1.79-4-4 0-.44.079-.881.219-1.281z'})); -export const iconMove = () => icon(h('path', {d: 'M3.5 0l-1.5 1.5h1v1.5h-1.5v-1l-1.5 1.5 1.5 1.5v-1h1.5v1.5h-1l1.5 1.5 1.5-1.5h-1v-1.5h1.5v1l1.5-1.5-1.5-1.5v1h-1.5v-1.5h1l-1.5-1.5z'})); -export const iconMusicalNote = () => icon(h('path', {d: 'M8 0c-5 0-6 1-6 1v4.094c-.154-.054-.327-.094-.5-.094-.828 0-1.5.672-1.5 1.5s.672 1.5 1.5 1.5 1.5-.672 1.5-1.5v-3.969c.732-.226 1.99-.438 4-.5v2.063c-.154-.054-.327-.094-.5-.094-.828 0-1.5.672-1.5 1.5s.672 1.5 1.5 1.5 1.5-.672 1.5-1.5v-5.5z'})); -export const iconPaperclip = () => icon(h('path', {d: 'M5 0c-.514 0-1.021.201-1.406.594l-2.781 2.719c-1.07 1.07-1.07 2.805 0 3.875 1.07 1.07 2.805 1.07 3.875 0l1.25-1.25-.688-.688-.906.875-.344.375c-.69.69-1.81.69-2.5 0-.682-.682-.668-1.778 0-2.469l2.781-2.719v-.031c.389-.395 1.037-.4 1.438 0 .388.381.378 1.006 0 1.406l-2.5 2.469c-.095.095-.28.095-.375 0-.095-.095-.095-.28 0-.375l.375-.344.594-.625-.688-.688-.875.875-.094.094c-.485.485-.485 1.265 0 1.75.485.485 1.265.485 1.75 0l2.5-2.438c.78-.78.785-2.041 0-2.813-.39-.39-.893-.594-1.406-.594z'})); -export const iconPencil = () => icon(h('path', {d: 'M6 0l-1 1 2 2 1-1-2-2zm-2 2l-4 4v2h2l4-4-2-2z'})); -export const iconPeople = () => icon(h('path', {d: 'M5.5 0c-.51 0-.949.355-1.219.875.45.54.719 1.275.719 2.125 0 .29-.034.574-.094.844.18.11.374.156.594.156.83 0 1.5-.9 1.5-2s-.67-2-1.5-2zm-3 1c-.828 0-1.5.895-1.5 2s.672 2 1.5 2 1.5-.895 1.5-2-.672-2-1.5-2zm4.75 3.156c-.43.51-1.018.824-1.688.844.27.38.438.844.438 1.344v.656h2v-1.656c0-.52-.31-.968-.75-1.188zm-6.5 1c-.44.22-.75.668-.75 1.188v1.656h5v-1.656c0-.52-.31-.968-.75-1.188-.44.53-1.06.844-1.75.844s-1.31-.314-1.75-.844z'})); -export const iconPerson = () => icon(h('path', {d: 'M4 0c-1.105 0-2 1.119-2 2.5s.895 2.5 2 2.5 2-1.119 2-2.5-.895-2.5-2-2.5zm-2.094 5c-1.07.04-1.906.92-1.906 2v1h8v-1c0-1.08-.836-1.96-1.906-2-.54.61-1.284 1-2.094 1-.81 0-1.554-.39-2.094-1z'})); -export const iconPhone = () => icon(h('path', {d: 'M1.188 0c-.11 0-.188.077-.188.188v7.625c0 .11.077.188.188.188h4.625c.11 0 .188-.077.188-.188v-7.625c0-.11-.077-.188-.188-.188h-4.625zm.813 1h3v5h-3v-5zm1.5 5.5c.28 0 .5.22.5.5s-.22.5-.5.5-.5-.22-.5-.5.22-.5.5-.5z'})); -export const iconPieChart = () => icon(h('path', {d: 'M3.5 0c-.97 0-1.839.391-2.469 1.031l2.969 2.969v-3.969c-.16-.03-.33-.031-.5-.031zm1.5 1.063v3.406l-2.719 2.719c.6.5 1.369.813 2.219.813 1.93 0 3.5-1.57 3.5-3.5 0-1.76-1.31-3.197-3-3.438zm-4.094 1.313c-.55.54-.906 1.285-.906 2.125 0 .95.435 1.804 1.125 2.344l2.156-2.125-2.375-2.344z'})); -export const iconPin = () => icon(h('path', {d: 'M1.344 0a.502.502 0 0 0 .156 1h.5v2h-1c-.55 0-1 .45-1 1h3v3l.438 1 .563-1v-3h3c0-.55-.45-1-1-1h-1v-2h.5a.5.5 0 1 0 0-1h-4a.5.5 0 0 0-.094 0 .502.502 0 0 0-.063 0z'})); -export const iconPlayCircle = () => icon(h('path', {d: 'M4 0c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm-1 2l3 2-3 2v-4z'})); -export const iconPlus = () => icon(h('path', {d: 'M3 0v3h-3v2h3v3h2v-3h3v-2h-3v-3h-2z'})); -export const iconPowerStandby = () => icon(h('path', {d: 'M3 0v4h1v-4h-1zm-1.281 1.438l-.375.313c-.803.64-1.344 1.634-1.344 2.75 0 1.929 1.571 3.5 3.5 3.5s3.5-1.571 3.5-3.5c0-1.116-.529-2.11-1.344-2.75l-.375-.313-.625.781.375.313c.585.46.969 1.165.969 1.969 0 1.391-1.109 2.5-2.5 2.5s-2.5-1.109-2.5-2.5c0-.804.361-1.509.938-1.969l.406-.313-.625-.781z'})); -export const iconPrint = () => icon(h('path', {d: 'M2 0v2h4v-2h-4zm-1.906 3c-.06 0-.094.034-.094.094v2.813c0 .06.034.094.094.094h.906v-2h6v2h.906c.06 0 .094-.034.094-.094v-2.813c0-.06-.034-.094-.094-.094h-7.813zm1.906 2v3h4v-3h-4z'})); -export const iconProject = () => icon(h('path', {d: 'M0 0v7h1v-7h-1zm7 0v7h1v-7h-1zm-5 1v1h2v-1h-2zm1 2v1h2v-1h-2zm1 2v1h2v-1h-2z'})); -export const iconPulse = () => icon(h('path', {d: 'M3.25 0l-.469 1.531-.781 2.563-.031-.063-.094-.344h-1.875v1h1.156l.375 1.156.469 1.469.469-1.469.781-2.5.781 2.5.406 1.313.531-1.281.594-1.469.125.281h2.313v-1h-1.688l-.375-.719-.5-1-.406 1.031-.469 1.188-.844-2.656-.469-1.531z'})); -export const iconPuzzlePiece = () => icon(h('path', {d: 'M3 0c-.28 0-.539.101-.719.281-.18.18-.281.439-.281.719 0 .28.181.479.281.719.03.06.063.161.063.281h-2.344v6h2.344c0-.12-.011-.221-.031-.281-.11-.24-.313-.439-.313-.719 0-.28.101-.539.281-.719.18-.18.439-.281.719-.281.28 0 .539.101.719.281.18.18.281.439.281.719 0 .28-.181.479-.281.719-.03.06-.063.161-.063.281h2.344v-2.344c.12 0 .221.011.281.031.24.11.439.313.719.313.28 0 .539-.101.719-.281.18-.18.281-.439.281-.719 0-.28-.101-.539-.281-.719-.18-.18-.439-.281-.719-.281-.28 0-.479.181-.719.281-.06.03-.161.063-.281.063v-2.344h-2.344c0-.12.011-.221.031-.281.11-.24.313-.439.313-.719 0-.28-.101-.539-.281-.719-.18-.18-.439-.281-.719-.281z'})); -export const iconRandom = () => icon(h('path', {d: 'M6 0v1h-.5c-.354 0-.6.116-.813.375l-1.406 1.75-1.5-1.75v-.031c-.212-.236-.427-.344-.781-.344h-1v1h1.031v.031l1.625 1.906-1.625 2.031v.031h-1.031v1h1c.354 0 .6-.116.813-.375l1.531-1.906 1.625 1.906v.031c.212.236.427.344.781.344h.25v1l2-1.5-2-1.5v1h-.281v-.031l-1.75-2.063 1.5-1.875v-.031h.531v1l2-1.5-2-1.5z'})); -export const iconReload = () => icon(h('path', {d: 'M4 0c-2.201 0-4 1.799-4 4s1.799 4 4 4c1.104 0 2.092-.456 2.813-1.188l-.688-.688c-.54.548-1.289.875-2.125.875-1.659 0-3-1.341-3-3s1.341-3 3-3c.834 0 1.545.354 2.094.906l-1.094 1.094h3v-3l-1.188 1.188c-.731-.72-1.719-1.188-2.813-1.188z'})); -export const iconResizeBoth = () => icon(h('path', {d: 'M4 0l1.656 1.656-4 4-1.656-1.656v4h4l-1.656-1.656 4-4 1.656 1.656v-4h-4z'})); -export const iconResizeHeight = () => icon(h('path', {d: 'M3.5 0l-2.5 3h2v2h-2l2.5 3 2.5-3h-2v-2h2l-2.5-3z'})); -export const iconResizeWidth = () => icon(h('path', {d: 'M3 1l-3 2.5 3 2.5v-2h2v2l3-2.5-3-2.5v2h-2v-2z'})); -export const iconRssAlt = () => icon(h('path', {d: 'M0 0v2c3.331 0 6 2.669 6 6h2c0-4.409-3.591-8-8-8zm0 3v2c1.67 0 3 1.33 3 3h2c0-2.75-2.25-5-5-5zm0 3v2h2c0-1.11-.89-2-2-2z'})); -export const iconRss = () => icon(h('path', {d: 'M1 0v1c3.32 0 6 2.68 6 6h1c0-3.86-3.14-7-7-7zm0 2v1c2.221 0 4 1.779 4 4h1c0-2.759-2.241-5-5-5zm0 2v1c1.109 0 2 .891 2 2h1c0-1.651-1.349-3-3-3zm0 2c-.552 0-1 .448-1 1s.448 1 1 1 1-.448 1-1-.448-1-1-1z'})); -export const iconScript = () => icon(h('path', {d: 'M3 0c-.55 0-1 .45-1 1v5.5c0 .28-.22.5-.5.5s-.5-.22-.5-.5v-1.5h-1v2c0 .55.45 1 1 1h5c.55 0 1-.45 1-1v-3h-4v-2.5c0-.28.22-.5.5-.5s.5.22.5.5v1.5h4v-2c0-.55-.45-1-1-1h-4z'})); -export const iconShareBoxed = () => icon(h('path', {d: 'M.75 0c-.402 0-.75.348-.75.75v5.5c0 .402.348.75.75.75h4.5c.402 0 .75-.348.75-.75v-1.25h-1v1h-4v-5h2v-1h-2.25zm5.25 0v1c-2.05 0-3.704 1.544-3.938 3.531.213-.875.999-1.531 1.938-1.531h2v1l2-2-2-2z'})); -export const iconShare = () => icon(h('path', {d: 'M5 0v2c-4 0-5 2.05-5 5 .52-1.98 2-3 4-3h1v2l3-3.156-3-2.844z'})); -export const iconShield = () => icon(h('path', {d: 'M4 0l-.188.094-3.5 1.469-.313.125v.313c0 1.657.666 3.122 1.469 4.188.401.533.828.969 1.25 1.281.422.313.826.531 1.281.531.455 0 .86-.219 1.281-.531.422-.313.849-.749 1.25-1.281.803-1.065 1.469-2.53 1.469-4.188v-.313l-.313-.125-3.5-1.469-.188-.094zm0 1.094v5.906c-.045 0-.328-.069-.656-.313s-.714-.631-1.063-1.094c-.642-.851-1.137-2.025-1.219-3.281l2.938-1.219z'})); -export const iconSignal = () => icon(h('path', {d: 'M6 0v8h1v-8h-1zm-2 1v7h1v-7h-1zm-2 2v5h1v-5h-1zm-2 2v3h1v-3h-1z'})); -export const iconSignpost = () => icon(h('path', {d: 'M3 0v1h-2l-1 1 1 1h2v5h1v-4h2l1-1-1-1h-2v-2h-1z'})); -export const iconSortAscending = () => icon(h('path', {d: 'M2 0v6h-2l2.5 2 2.5-2h-2v-6h-1zm2 0v1h2v-1h-2zm0 2v1h3v-1h-3zm0 2v1h4v-1h-4z'})); -export const iconSortDescending = () => icon(h('path', {d: 'M2 0v6h-2l2.5 2 2.5-2h-2v-6h-1zm2 0v1h4v-1h-4zm0 2v1h3v-1h-3zm0 2v1h2v-1h-2z'})); -export const iconSpreadsheet = () => icon(h('path', {d: 'M.75 0c-.402 0-.75.348-.75.75v5.5c0 .402.348.75.75.75h6.5c.402 0 .75-.348.75-.75v-5.5c0-.402-.348-.75-.75-.75h-6.5zm.25 1h1v1h-1v-1zm2 0h4v1h-4v-1zm-2 2h1v1h-1v-1zm2 0h4v1h-4v-1zm-2 2h1v1h-1v-1zm2 0h4v1h-4v-1z'})); -export const iconStar = () => icon(h('path', {d: 'M4 0l-1 3h-3l2.5 2-1 3 2.5-2 2.5 2-1-3 2.5-2h-3l-1-3z'})); -export const iconSun = () => icon(h('path', {d: 'M4 0c-.276 0-.5.224-.5.5s.224.5.5.5.5-.224.5-.5-.224-.5-.5-.5zm-2.5 1c-.276 0-.5.224-.5.5s.224.5.5.5.5-.224.5-.5-.224-.5-.5-.5zm5 0c-.276 0-.5.224-.5.5s.224.5.5.5.5-.224.5-.5-.224-.5-.5-.5zm-2.5 1c-1.105 0-2 .895-2 2s.895 2 2 2 2-.895 2-2-.895-2-2-2zm-3.5 1.5c-.276 0-.5.224-.5.5s.224.5.5.5.5-.224.5-.5-.224-.5-.5-.5zm7 0c-.276 0-.5.224-.5.5s.224.5.5.5.5-.224.5-.5-.224-.5-.5-.5zm-6 2.5c-.276 0-.5.224-.5.5s.224.5.5.5.5-.224.5-.5-.224-.5-.5-.5zm5 0c-.276 0-.5.224-.5.5s.224.5.5.5.5-.224.5-.5-.224-.5-.5-.5zm-2.5 1c-.276 0-.5.224-.5.5s.224.5.5.5.5-.224.5-.5-.224-.5-.5-.5z'})); -export const iconTablet = () => icon(h('path', {d: 'M.344 0c-.18 0-.344.164-.344.344v7.313c0 .18.164.344.344.344h6.313c.18 0 .344-.164.344-.344v-7.313c0-.18-.164-.344-.344-.344h-6.313zm.656 1h5v5h-5v-5zm2.5 5.5c.28 0 .5.22.5.5s-.22.5-.5.5-.5-.22-.5-.5.22-.5.5-.5z'})); -export const iconTag = () => icon(h('path', {d: 'M0 0v3l5 5 3-3-5-5h-3zm2 1c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1z'})); -export const iconTags = () => icon(h('path', {d: 'M0 1v2l3 3 1.5-1.5.5-.5-2-2-1-1h-2zm3.406 0l3 3-1.188 1.219.781.781 2-2-3-3h-1.594zm-1.906 1c.28 0 .5.22.5.5s-.22.5-.5.5-.5-.22-.5-.5.22-.5.5-.5z'})); -export const iconTarget = () => icon(h('path', {d: 'M4 0c-2.203 0-4 1.797-4 4 0 2.203 1.797 4 4 4 2.203 0 4-1.797 4-4 0-2.203-1.797-4-4-4zm0 1c1.663 0 3 1.337 3 3s-1.337 3-3 3-3-1.337-3-3 1.337-3 3-3zm0 1c-1.099 0-2 .901-2 2s.901 2 2 2 2-.901 2-2-.901-2-2-2zm0 1c.558 0 1 .442 1 1s-.442 1-1 1-1-.442-1-1 .442-1 1-1z'})); -export const iconTask = () => icon(h('path', {d: 'M0 0v7h7v-3.594l-1 1v1.594h-5v-5h3.594l1-1h-5.594zm7 0l-3 3-1-1-1 1 2 2 4-4-1-1z'})); -export const iconTerminal = () => icon(h('path', {d: 'M.094 0c-.06 0-.094.034-.094.094v7.813c0 .06.034.094.094.094h7.813c.06 0 .094-.034.094-.094v-7.813c0-.06-.034-.094-.094-.094h-7.813zm1.406.781l1.719 1.719-1.719 1.719-.719-.719 1-1-1-1 .719-.719zm2.5 2.219h3v1h-3v-1z'})); -export const iconText = () => icon(h('path', {d: 'M0 0v2h.5c0-.55.45-1 1-1h1.5v5.5c0 .28-.22.5-.5.5h-.5v1h4v-1h-.5c-.28 0-.5-.22-.5-.5v-5.5h1.5c.55 0 1 .45 1 1h.5v-2h-8z'})); -export const iconThumbDown = () => icon(h('path', {d: 'M0 0v4h1v-4h-1zm2 0v4.001c.28 0 .529.101.719.281.18.19 1.151 2.115 1.281 2.375.13.26.386.393.656.313.26-.08.393-.355.313-.625-.08-.26-.469-1.594-.469-1.844s.22-.5.5-.5h1.5c.28 0 .5-.22.5-.5l-1.031-3.188c-.08-.18-.259-.313-.469-.313h-3.5z'})); -export const iconThumbUp = () => icon(h('path', {d: 'M4.438 0c-.19.021-.34.149-.438.344-.13.26-1.101 2.185-1.281 2.375-.19.18-.439.281-.719.281v4.001h3.5c.21 0 .389-.133.469-.313 0 0 1.031-2.908 1.031-3.188 0-.28-.22-.5-.5-.5h-1.5c-.28 0-.5-.25-.5-.5s.389-1.574.469-1.844c.08-.27-.053-.545-.313-.625l-.219-.031zm-4.438 3v4h1v-4h-1z'})); -export const iconTimer = () => icon(h('path', {d: 'M2 0v1h1v.031c-1.697.241-3 1.707-3 3.469 0 1.929 1.571 3.5 3.5 3.5s3.5-1.571 3.5-3.5c0-.45-.086-.874-.219-1.25l-.938.344c.107.304.156.596.156.906 0 1.391-1.109 2.5-2.5 2.5s-2.5-1.109-2.5-2.5 1.109-2.5 2.5-2.5c.298 0 .585.051.875.156l.344-.938c-.221-.081-.471-.119-.719-.156v-.063h1v-1h-3zm5 1.125s-3.675 2.8-3.875 3c-.2.2-.2.519 0 .719.2.2.519.2.719 0 .2-.19 3.156-3.719 3.156-3.719z'})); -export const iconTransfer = () => icon(h('path', {d: 'M6 0v1h-6v1h6v1l2-1.5-2-1.5zm-4 4l-2 1.5 2 1.5v-1h6v-1h-6v-1z'})); -export const iconTrash = () => icon(h('path', {d: 'M3 0c-.55 0-1 .45-1 1h-1c-.55 0-1 .45-1 1h7c0-.55-.45-1-1-1h-1c0-.55-.45-1-1-1h-1zm-2 3v4.813c0 .11.077.188.188.188h4.625c.11 0 .188-.077.188-.188v-4.813h-1v3.5c0 .28-.22.5-.5.5s-.5-.22-.5-.5v-3.5h-1v3.5c0 .28-.22.5-.5.5s-.5-.22-.5-.5v-3.5h-1z'})); -export const iconUnderline = () => icon(h('path', {d: 'M1 0v4c0 1.1 1.12 2 2.5 2h.5c1.1 0 2-.9 2-2v-4h-1v4c0 .55-.45 1-1 1s-1-.45-1-1v-4h-2zm-1 7v1h7v-1h-7z'})); -export const iconVerticalAlignBottom = () => icon(h('path', {d: 'M.094 0c-.06 0-.094.034-.094.094v4.813c0 .06.034.094.094.094h1.813c.06 0 .094-.034.094-.094v-4.813c0-.06-.034-.094-.094-.094h-1.813zm6 0c-.06 0-.094.034-.094.094v4.813c0 .06.034.094.094.094h1.813c.06 0 .094-.034.094-.094v-4.813c0-.06-.034-.094-.094-.094h-1.813zm-3 2c-.06 0-.094.034-.094.094v2.813c0 .06.034.094.094.094h1.813c.06 0 .094-.034.094-.094v-2.813c0-.06-.034-.094-.094-.094h-1.813zm-3.094 4v1h8v-1h-8z'})); -export const iconVerticalAlignCenter = () => icon(h('path', {d: 'M.094 0c-.06 0-.094.034-.094.094v1.906h2v-1.906c0-.06-.034-.094-.094-.094h-1.813zm6 0c-.06 0-.094.034-.094.094v1.906h2v-1.906c0-.06-.034-.094-.094-.094h-1.813zm-3 1c-.06 0-.094.034-.094.094v.906h2v-.906c0-.06-.034-.094-.094-.094h-1.813zm-3.094 2v1h8v-1h-8zm0 2v1.906c0 .06.034.094.094.094h1.813c.06 0 .094-.034.094-.094v-1.906h-2zm3 0v.906c0 .06.034.094.094.094h1.813c.06 0 .094-.034.094-.094v-.906h-2zm3 0v1.906c0 .06.034.094.094.094h1.813c.06 0 .094-.034.094-.094v-1.906h-2z'})); -export const iconVerticalAlignTop = () => icon(h('path', {d: 'M0 0v1h8v-1h-8zm.094 2c-.06 0-.094.034-.094.094v4.813c0 .06.034.094.094.094h1.813c.06 0 .094-.034.094-.094v-4.813c0-.06-.034-.094-.094-.094h-1.813zm3 0c-.06 0-.094.034-.094.094v2.813c0 .06.034.094.094.094h1.813c.06 0 .094-.034.094-.094v-2.813c0-.06-.034-.094-.094-.094h-1.813zm3 0c-.06 0-.094.034-.094.094v4.813c0 .06.034.094.094.094h1.813c.06 0 .094-.034.094-.094v-4.813c0-.06-.034-.094-.094-.094h-1.813z'})); -export const iconVideo = () => icon(h('path', {d: 'M.5 1c-.28 0-.5.22-.5.5v4c0 .28.22.5.5.5h5c.28 0 .5-.22.5-.5v-1.5l1 1h1v-3h-1l-1 1v-1.5c0-.28-.22-.5-.5-.5h-5z'})); -export const iconVolumeHigh = () => icon(h('path', {d: 'M3.344 0l-1.344 2h-2v4h2l1.344 2h.656v-8h-.656zm1.656 1v1c.152 0 .313.026.469.063h.031c.86.215 1.5.995 1.5 1.938 0 .942-.64 1.722-1.5 1.938-.166.041-.338.063-.5.063v1c.258 0 .516-.035.75-.094 1.3-.325 2.25-1.508 2.25-2.906 0-1.398-.95-2.581-2.25-2.906-.234-.059-.492-.094-.75-.094zm0 2v2l.25-.031c.433-.118.75-.507.75-.969 0-.446-.325-.819-.75-.938v-.031h-.031l-.219-.031z'})); -export const iconVolumeLow = () => icon(h('path', {d: 'M4.344 0l-1.344 2h-2v4h2l1.344 2h.656v-8h-.656zm1.656 3v2l.25-.031c.433-.118.75-.507.75-.969 0-.446-.325-.819-.75-.938v-.031h-.031l-.219-.031z'})); -export const iconVolumeOff = () => icon(h('path', {d: 'M5.344 0l-1.344 2h-2v4h2l1.344 2h.656v-8h-.656z'})); -export const iconWarning = () => icon(h('path', {d: 'M3.094 0c-.06 0-.105.044-.125.094l-2.938 6.813-.031.188v.813c0 .06.034.094.094.094h6.813c.06 0 .094-.034.094-.094v-.813l-.031-.188-2.938-6.813c-.02-.05-.065-.094-.125-.094h-.813zm-.094 3h1v2h-1v-2zm0 3h1v1h-1v-1z'})); -export const iconWifi = () => icon(h('path', {d: 'M3.75 0c-1.374 0-2.66.372-3.75 1.063l.531.875c.93-.59 2.033-.938 3.219-.938 1.2 0 2.323.31 3.25.906l.531-.813c-1.093-.703-2.401-1.094-3.781-1.094zm.031 3c-.795 0-1.531.227-2.156.625l.531.844c.475-.302 1.02-.469 1.625-.469.593 0 1.13.177 1.594.469l.531-.844c-.616-.388-1.338-.625-2.125-.625zm-.031 3c-.552 0-1 .448-1 1s.448 1 1 1 1-.448 1-1-.448-1-1-1z'})); -export const iconWrench = () => icon(h('path', {d: 'M5.5 0c-1.38 0-2.5 1.12-2.5 2.5 0 .32.078.626.188.906l-2.906 2.875c-.39.39-.39 1.016 0 1.406.2.2.459.313.719.313.26 0 .519-.091.719-.281l2.875-2.875c.28.1.586.156.906.156 1.38 0 2.5-1.12 2.5-2.5 0-.16-.032-.297-.063-.438l-.938.938h-2v-2l.938-.938c-.14-.03-.277-.062-.438-.063zm-4.5 6.5c.28 0 .5.22.5.5s-.22.5-.5.5-.5-.22-.5-.5.22-.5.5-.5z'})); -export const iconX = () => icon(h('path', {d: 'M1.406 0l-1.406 1.406.688.719 1.781 1.781-1.781 1.781-.688.719 1.406 1.406.719-.688 1.781-1.781 1.781 1.781.719.688 1.406-1.406-.688-.719-1.781-1.781 1.781-1.781.688-.719-1.406-1.406-.719.688-1.781 1.781-1.781-1.781-.719-.688z'})); -export const iconZoomIn = () => icon(h('path', {d: 'M3.5 0c-1.927 0-3.5 1.573-3.5 3.5s1.573 3.5 3.5 3.5c.592 0 1.166-.145 1.656-.406a1 1 0 0 0 .094.094l1.031 1.031a1.016 1.016 0 1 0 1.438-1.438l-1.031-1.031a1 1 0 0 0-.125-.094c.266-.493.438-1.059.438-1.656 0-1.927-1.573-3.5-3.5-3.5zm0 1c1.387 0 2.5 1.113 2.5 2.5 0 .587-.196 1.137-.531 1.563l-.031.031a1 1 0 0 0-.063.031 1 1 0 0 0-.281.281 1 1 0 0 0-.063.063c-.422.326-.953.531-1.531.531-1.387 0-2.5-1.113-2.5-2.5s1.113-2.5 2.5-2.5zm-.5 1v1h-1v1h1v1h1v-1h1v-1h-1v-1h-1z'})); -export const iconZoomOut = () => icon(h('path', {d: 'M3.5 0c-1.927 0-3.5 1.573-3.5 3.5s1.573 3.5 3.5 3.5c.592 0 1.166-.145 1.656-.406a1 1 0 0 0 .094.094l1.031 1.031a1.016 1.016 0 1 0 1.438-1.438l-1.031-1.031a1 1 0 0 0-.125-.094c.266-.493.438-1.059.438-1.656 0-1.927-1.573-3.5-3.5-3.5zm0 1c1.387 0 2.5 1.113 2.5 2.5 0 .587-.196 1.137-.531 1.563l-.031.031a1 1 0 0 0-.063.031 1 1 0 0 0-.281.281 1 1 0 0 0-.063.063c-.422.326-.953.531-1.531.531-1.387 0-2.5-1.113-2.5-2.5s1.113-2.5 2.5-2.5zm-1.5 2v1h3v-1h-3z'})); +export const iconAccountLogin = () => icon(h('path', { d: 'M3 0v1h4v5h-4v1h5v-7h-5zm1 2v1h-4v1h4v1l2-1.5-2-1.5z' })); +export const iconAccountLogout = () => icon(h('path', { d: 'M3 0v1h4v5h-4v1h5v-7h-5zm-1 2l-2 1.5 2 1.5v-1h4v-1h-4v-1z' })); +export const iconActionRedo = () => icon(h('path', { d: 'M3.5 1c-1.93 0-3.5 1.57-3.5 3.5 0-1.38 1.12-2.5 2.5-2.5s2.5 1.12 2.5 2.5v.5h-1l2 2 2-2h-1v-.5c0-1.93-1.57-3.5-3.5-3.5z' })); +export const iconActionUndo = () => icon(h('path', { d: 'M4.5 1c-1.93 0-3.5 1.57-3.5 3.5v.5h-1l2 2 2-2h-1v-.5c0-1.38 1.12-2.5 2.5-2.5s2.5 1.12 2.5 2.5c0-1.93-1.57-3.5-3.5-3.5z' })); +export const iconAlignCenter = () => icon(h('path', { d: 'M0 0v1h8v-1h-8zm1 2v1h6v-1h-6zm-1 2v1h8v-1h-8zm1 2v1h6v-1h-6z' })); +export const iconAlignLeft = () => icon(h('path', { d: 'M0 0v1h8v-1h-8zm0 2v1h6v-1h-6zm0 2v1h8v-1h-8zm0 2v1h6v-1h-6z' })); +export const iconAlignRight = () => icon(h('path', { d: 'M0 0v1h8v-1h-8zm2 2v1h6v-1h-6zm-2 2v1h8v-1h-8zm2 2v1h6v-1h-6z' })); +export const iconArrowCircleBottom = () => icon(h('path', { d: 'M4 0c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm-1 1h2v3h2l-3 3-3-3h2v-3z' })); +export const iconArrowCircleLeft = () => icon(h('path', { d: 'M4 0c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm0 1v2h3v2h-3v2l-3-3 3-3z' })); +export const iconArrowCircleRight = () => icon(h('path', { d: 'M4 0c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm0 1l3 3-3 3v-2h-3v-2h3v-2z' })); +export const iconArrowCircleTop = () => icon(h('path', { d: 'M4 0c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm0 1l3 3h-2v3h-2v-3h-2l3-3z' })); +export const iconArrowBottom = () => icon(h('path', { d: 'M3 0v5h-2l2.531 3 2.469-3h-2v-5h-1z' })); +export const iconArrowLeft = () => icon(h('path', { d: 'M3 1l-3 2.531 3 2.469v-2h5v-1h-5v-2z' })); +export const iconArrowRight = () => icon(h('path', { d: 'M5 1v2h-5v1h5v2l3-2.531-3-2.469z' })); +export const iconArrowTop = () => icon(h('path', { d: 'M3.469 0l-2.469 3h2v5h1v-5h2l-2.531-3z' })); +export const iconArrowThickBottom = () => icon(h('path', { d: 'M3 0v5h-2l3.031 3 2.969-3h-2v-5h-2z' })); +export const iconArrowThickLeft = () => icon(h('path', { d: 'M3 1l-3 3.031 3 2.969v-2h5v-2h-5v-2z' })); +export const iconArrowThickRight = () => icon(h('path', { d: 'M5 1v2h-5v2h5v2l3-3.031-3-2.969z' })); +export const iconArrowThickTop = () => icon(h('path', { d: 'M3.969 0l-2.969 3h2v5h2v-5h2l-3.031-3z' })); +export const iconAudioSpectrum = () => icon(h('path', { d: 'M4 0v8h1v-8h-1zm-2 1v6h1v-6h-1zm4 1v4h1v-4h-1zm-6 1v2h1v-2h-1z' })); +export const iconAudio = () => icon(h('path', { d: 'M1.188 1c-.734.722-1.188 1.748-1.188 2.844 0 1.095.454 2.09 1.188 2.813l.688-.719c-.546-.538-.875-1.269-.875-2.094s.329-1.587.875-2.125l-.688-.719zm5.625 0l-.688.719c.552.552.875 1.289.875 2.125 0 .836-.327 1.554-.875 2.094l.688.719c.732-.72 1.188-1.708 1.188-2.813 0-1.104-.459-2.115-1.188-2.844zm-4.219 1.406c-.362.362-.594.889-.594 1.438 0 .548.232 1.045.594 1.406l.688-.719c-.178-.178-.281-.416-.281-.688 0-.272.103-.54.281-.719l-.688-.719zm2.813 0l-.688.719c.183.183.281.434.281.719s-.099.505-.281.688l.688.719c.357-.357.594-.851.594-1.406 0-.555-.236-1.08-.594-1.438z' })); +export const iconBadge = () => icon(h('path', { d: 'M4 0c-1.105 0-2 .895-2 2s.895 2 2 2 2-.895 2-2-.895-2-2-2zm-1 4.813v3.188l1-1 1 1v-3.188c-.31.11-.65.188-1 .188s-.69-.077-1-.188z' })); +export const iconBan = () => icon(h('path', { d: 'M4 0c-2.203 0-4 1.797-4 4 0 2.203 1.797 4 4 4 2.203 0 4-1.797 4-4 0-2.203-1.797-4-4-4zm0 1c.655 0 1.258.209 1.75.563l-4.188 4.188c-.353-.492-.563-1.095-.563-1.75 0-1.663 1.337-3 3-3zm2.438 1.25c.353.492.563 1.095.563 1.75 0 1.663-1.337 3-3 3-.655 0-1.258-.209-1.75-.563l4.188-4.188z' })); +export const iconBarChart = () => icon(h('path', { d: 'M0 0v7h8v-1h-7v-6h-1zm5 0v5h2v-5h-2zm-3 2v3h2v-3h-2z' })); +export const iconBasket = () => icon(h('path', { d: 'M3.969 0c-.127.011-.259.083-.344.188l-2.344 2.813h-1.281v1h1v3.656c0 .18.164.344.344.344h5.313c.18 0 .344-.164.344-.344v-3.656h1v-1h-1.281c-.274-.329-2.387-2.866-2.406-2.875-.105-.09-.216-.136-.344-.125zm.031 1.281l1.438 1.719h-2.875l1.438-1.719zm-1.5 3.719c.28 0 .5.22.5.5v1c0 .28-.22.5-.5.5s-.5-.22-.5-.5v-1c0-.28.22-.5.5-.5zm3 0c.28 0 .5.22.5.5v1c0 .28-.22.5-.5.5s-.5-.22-.5-.5v-1c0-.28.22-.5.5-.5z' })); +export const iconBatteryEmpty = () => icon(h('path', { d: 'M.094 1c-.06 0-.094.034-.094.094v5.813c0 .06.034.094.094.094h6.813c.06 0 .094-.034.094-.094v-1.906h1v-2h-1v-1.906c0-.06-.034-.094-.094-.094h-6.813zm.906 1h5v4h-5v-4z' })); +export const iconBatteryFull = () => icon(h('path', { d: 'M.094 1c-.06 0-.094.034-.094.094v5.813c0 .06.034.094.094.094h6.813c.06 0 .094-.034.094-.094v-1.906h1v-2h-1v-1.906c0-.06-.034-.094-.094-.094h-6.813z' })); +export const iconBeaker = () => icon(h('path', { d: 'M1.344 0a.502.502 0 0 0 .156 1h.5v1.406c-.088.172-1.194 2.313-1.656 3.094-.153.268-.344.612-.344 1.063 0 .383.139.764.406 1.031.26.26.643.406 1.031.406h5.125c.383 0 .764-.139 1.031-.406.26-.26.406-.643.406-1.031 0-.452-.194-.801-.344-1.063-.463-.78-1.568-2.922-1.656-3.094v-1.406h.5a.5.5 0 1 0 0-1h-5a.5.5 0 0 0-.094 0 .502.502 0 0 0-.063 0zm1.656 1h2v1.625l.063.094s.652 1.233 1.219 2.281h-4.563c.567-1.049 1.219-2.281 1.219-2.281l.063-.094v-1.625z' })); +export const iconBell = () => icon(h('path', { d: 'M4 0c-1.1 0-2 .9-2 2 0 1.04-.524 1.976-1.344 2.656-.42.34-.656.824-.656 1.344h8c0-.52-.236-1.004-.656-1.344-.82-.68-1.344-1.616-1.344-2.656 0-1.1-.9-2-2-2zm-1 7c0 .55.45 1 1 1s1-.45 1-1h-2z' })); +export const iconBold = () => icon(h('path', { d: 'M0 0v1c.55 0 1 .45 1 1v4c0 .55-.45 1-1 1v1h5.5c1.38 0 2.5-1.12 2.5-2.5 0-1-.588-1.85-1.438-2.25.27-.34.438-.78.438-1.25 0-1.1-.9-2-2-2h-5zm3 1h1c.55 0 1 .45 1 1s-.45 1-1 1h-1v-2zm0 3h1.5c.83 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5h-1.5v-3z' })); +export const iconBolt = () => icon(h('path', { d: 'M4 0l-3 5h2v3l3-5h-2v-3z' })); +export const iconBook = () => icon(h('path', { d: 'M1 0l-.188.031c-.39.08-.701.391-.781.781l-.031.188v5.5c0 .83.67 1.5 1.5 1.5h5.5v-1h-5.5c-.28 0-.5-.22-.5-.5s.22-.5.5-.5h5.5v-5.5c0-.28-.22-.5-.5-.5h-.5v3l-1-1-1 1v-3h-3z' })); +export const iconBookmark = () => icon(h('path', { d: 'M2 0v8l2-2 2 2v-8h-4z' })); +export const iconBox = () => icon(h('path', { d: 'M0 0v1h8v-1h-8zm0 2v5.906c0 .06.034.094.094.094h7.813c.06 0 .094-.034.094-.094v-5.906h-2.969v1.031h-2.031v-1.031h-3z' })); +export const iconBriefcase = () => icon(h('path', { d: 'M3 0c-.554 0-1 .458-1 1v1h-1.906c-.06 0-.094.034-.094.094v2.406c0 .28.22.5.5.5h7c.28 0 .5-.22.5-.5v-2.406c0-.06-.034-.094-.094-.094h-1.906v-1c0-.542-.446-1-1-1h-2zm0 1h2v1h-2v-1zm-3 4.906v2c0 .06.034.094.094.094h7.813c.06 0 .094-.034.094-.094v-2c-.16.05-.32.094-.5.094h-7c-.18 0-.34-.044-.5-.094z' })); +export const iconBrowser = () => icon(h('path', { d: 'M.344 0a.5.5 0 0 0-.344.5v7a.5.5 0 0 0 .5.5h7a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.5-.5h-7a.5.5 0 0 0-.094 0 .5.5 0 0 0-.063 0zm1.156 1c.28 0 .5.22.5.5s-.22.5-.5.5-.5-.22-.5-.5.22-.5.5-.5zm2 0h3c.28 0 .5.22.5.5s-.22.5-.5.5h-3c-.28 0-.5-.22-.5-.5s.22-.5.5-.5zm-2.5 2h6v4h-6v-4z' })); +export const iconBrush = () => icon(h('path', { d: 'M7.438.031l-.063.031-3.75 2.656-.125.156-.125.25c.719.229 1.271.781 1.5 1.5l.25-.125c.05-.02.126-.075.156-.125l2.656-3.75c.03-.04.04-.116 0-.156l-.406-.406-.094-.031zm-4.781 3.969c-.73 0-1.313.614-1.313 1.344 0 .99-.544 1.821-1.344 2.281.4.23.864.375 1.344.375 1.48 0 2.656-1.176 2.656-2.656 0-.73-.604-1.344-1.344-1.344z' })); +export const iconBug = () => icon(h('path', { d: 'M3.5 0c-1.19 0-1.978 1.69-1.188 2.5l-.281.219-1.313-.656a.5.5 0 0 0-.344-.063.5.5 0 0 0-.094.938l1.156.563c-.09.156-.186.328-.25.5h-.688a.5.5 0 0 0-.094 0 .502.502 0 1 0 .094 1h.5c0 .227.023.445.063.656l-.781.406a.5.5 0 1 0 .438.875l.656-.344c.245.46.59.844 1 1.094.35-.19.625-.439.625-.719v-1.438a.5.5 0 0 0 0-.094v-.813a.5.5 0 0 0 0-.219c.045-.231.254-.406.5-.406.28 0 .5.22.5.5v.875a.5.5 0 0 0 0 .094v.063a.5.5 0 0 0 0 .094v1.344c0 .27.275.497.625.688.41-.245.755-.604 1-1.063l.656.344a.5.5 0 1 0 .438-.875l-.781-.406c.04-.211.063-.429.063-.656h.5a.5.5 0 1 0 0-1h-.688c-.064-.172-.16-.344-.25-.5l1.156-.563a.5.5 0 0 0-.313-.938.5.5 0 0 0-.125.063l-1.313.656-.281-.219c.78-.83.003-2.5-1.188-2.5z' })); +export const iconBullhorn = () => icon(h('path', { d: 'M6.094 0l-.094.031v5.969h.907c.06 0 .094-.034.094-.094v-5.813c0-.06-.034-.094-.094-.094h-.813zm-1.094.5l-2.906 1.469-.188.031h-1.813c-.06 0-.094.034-.094.094v1.813c0 .06.034.094.094.094h.906l1.031 2.719c.11.25.406.36.656.25.25-.11.36-.406.25-.656l-.719-1.781c.033-.136.136-.25.281-.25v-.031l2.5 1.25v-5z' })); +export const iconCalculator = () => icon(h('path', { d: 'M.094 0c-.06 0-.094.034-.094.094v7.813c0 .06.034.094.094.094h6.813c.06 0 .094-.034.094-.094v-7.813c0-.06-.034-.094-.094-.094h-6.813zm.906 1h5v2h-5v-2zm0 3h1v1h-1v-1zm2 0h1v1h-1v-1zm2 0h1v3h-1v-3zm-4 2h1v1h-1v-1zm2 0h1v1h-1v-1z' })); +export const iconCalendar = () => icon(h('path', { d: 'M0 0v2h7v-2h-7zm0 3v4.906c0 .06.034.094.094.094h6.813c.06 0 .094-.034.094-.094v-4.906h-7zm1 1h1v1h-1v-1zm2 0h1v1h-1v-1zm2 0h1v1h-1v-1zm-4 2h1v1h-1v-1zm2 0h1v1h-1v-1z' })); +export const iconCameraSlr = () => icon(h('path', { d: 'M4.094 0c-.06 0-.105.044-.125.094l-.938 1.813c-.02.05-.065.094-.125.094h-1.406c-.83 0-1.5.67-1.5 1.5v4.406c0 .06.034.094.094.094h7.813c.06 0 .094-.034.094-.094v-5.813c0-.06-.034-.094-.094-.094h-.813c-.06 0-.105-.044-.125-.094l-.938-1.813c-.02-.05-.065-.094-.125-.094h-1.813zm-2.594 3c.28 0 .5.22.5.5s-.22.5-.5.5-.5-.22-.5-.5.22-.5.5-.5zm3.5 0c1.1 0 2 .9 2 2s-.9 2-2 2-2-.9-2-2 .9-2 2-2zm0 1c-.55 0-1 .45-1 1s.45 1 1 1 1-.45 1-1-.45-1-1-1z' })); +export const iconCaretBottom = () => icon(h('path', { d: 'M0 2l4 4 4-4h-8z' })); +export const iconCaretLeft = () => icon(h('path', { d: 'M6 0l-4 4 4 4v-8z' })); +export const iconCaretRight = () => icon(h('path', { d: 'M2 0v8l4-4-4-4z' })); +export const iconCaretTop = () => icon(h('path', { d: 'M4 2l-4 4h8l-4-4z' })); +export const iconChat = () => icon(h('path', { d: 'M0 0v5l1-1h1v-3h3v-1h-5zm3 2v4h4l1 1v-5h-5z' })); +export const iconCheck = () => icon(h('path', { d: 'M6.406 1l-.719.688-2.781 2.781-.781-.781-.719-.688-1.406 1.406.688.719 1.5 1.5.719.688.719-.688 3.5-3.5.688-.719-1.406-1.406z' })); +export const iconChevronBottom = () => icon(h('path', { d: 'M1.5 1l-1.5 1.5 4 4 4-4-1.5-1.5-2.5 2.5-2.5-2.5z' })); +export const iconChevronLeft = () => icon(h('path', { d: 'M5 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z' })); +export const iconChevronRight = () => icon(h('path', { d: 'M2.5 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z' })); +export const iconChevronTop = () => icon(h('path', { d: 'M4 1l-4 4 1.5 1.5 2.5-2.5 2.5 2.5 1.5-1.5-4-4z' })); +export const iconCircleCheck = () => icon(h('path', { d: 'M4 0c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm2 1.781l.719.719-3.219 3.219-1.719-1.719.719-.719 1 1 2.5-2.5z' })); +export const iconCircleX = () => icon(h('path', { d: 'M4 0c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm-1.5 1.781l1.5 1.5 1.5-1.5.719.719-1.5 1.5 1.5 1.5-.719.719-1.5-1.5-1.5 1.5-.719-.719 1.5-1.5-1.5-1.5.719-.719z' })); +export const iconClipboard = () => icon(h('path', { d: 'M3.5 0c-.28 0-.5.22-.5.5v.5h-.75c-.14 0-.25.11-.25.25v.75h3v-.75c0-.14-.11-.25-.25-.25h-.75v-.5c0-.28-.22-.5-.5-.5zm-3.25 1c-.14 0-.25.11-.25.25v6.5c0 .14.11.25.25.25h6.5c.14 0 .25-.11.25-.25v-6.5c0-.14-.11-.25-.25-.25h-.75v2h-5v-2h-.75z' })); +export const iconClock = () => icon(h('path', { d: 'M4 0c-2.203 0-4 1.797-4 4 0 2.203 1.797 4 4 4 2.203 0 4-1.797 4-4 0-2.203-1.797-4-4-4zm0 1c1.663 0 3 1.337 3 3s-1.337 3-3 3-3-1.337-3-3 1.337-3 3-3zm-.5 1v2.219l.156.125.5.5.344.375.719-.719-.375-.344-.344-.344v-1.813h-1z' })); +export const iconCloudDownload = () => icon(h('path', { d: 'M4.5 0c-1.21 0-2.27.86-2.5 2-1.1 0-2 .9-2 2 0 .37.111.7.281 1h2.719v-.5c0-.83.67-1.5 1.5-1.5s1.5.67 1.5 1.5v.5h1.906c.05-.16.094-.32.094-.5 0-.65-.42-1.29-1-1.5v-.5c0-1.38-1.12-2.5-2.5-2.5zm-.156 4a.5.5 0 0 0-.344.5v1.5h-1.5l2 2 2-2h-1.5v-1.5a.5.5 0 0 0-.594-.5.5.5 0 0 0-.063 0z' })); +export const iconCloudUpload = () => icon(h('path', { d: 'M4.5 0c-1.21 0-2.27.86-2.5 2-1.1 0-2 .9-2 2 0 .37.111.7.281 1h2.219l2-2 2 2h1.406c.05-.16.094-.32.094-.5 0-.65-.42-1.29-1-1.5v-.5c0-1.38-1.12-2.5-2.5-2.5zm0 4.5l-2.5 2.5h2v.5a.5.5 0 1 0 1 0v-.5h2l-2.5-2.5z' })); +export const iconCloud = () => icon(h('path', { d: 'M4.5 1c-1.21 0-2.27.86-2.5 2-1.1 0-2 .9-2 2s.9 2 2 2h4.5c.83 0 1.5-.67 1.5-1.5 0-.65-.42-1.29-1-1.5v-.5c0-1.38-1.12-2.5-2.5-2.5z' })); +export const iconCode = () => icon(h('path', { d: 'M5 1l-3 6h1l3-6h-1zm-4 1l-1 2 1 2h1l-1-2 1-2h-1zm5 0l1 2-1 2h1l1-2-1-2h-1z' })); +export const iconCog = () => icon(h('path', { d: 'M3.5 0l-.5 1.188-.281.125-1.188-.5-.719.719.5 1.188-.125.281-1.188.5v1l1.188.5.125.313-.5 1.156.719.719 1.188-.5.281.125.5 1.188h1l.5-1.188.281-.125 1.188.5.719-.719-.5-1.188.125-.281 1.188-.5v-1l-1.188-.5-.125-.281.469-1.188-.688-.719-1.188.5-.281-.125-.5-1.188h-1zm.5 2.5c.83 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5-1.5-.67-1.5-1.5.67-1.5 1.5-1.5z' })); +export const iconCollapseDown = () => icon(h('path', { d: 'M0 0v2h8v-2h-8zm2 3l2 2 2-2h-4zm-2 4v1h8v-1h-8z' })); +export const iconCollapseLeft = () => icon(h('path', { d: 'M0 0v8h1v-8h-1zm6 0v8h2v-8h-2zm-1 2l-2 2 2 2v-4z' })); +export const iconCollapseRight = () => icon(h('path', { d: 'M0 0v8h2v-8h-2zm7 0v8h1v-8h-1zm-4 2v4l2-2-2-2z' })); +export const iconCollapseUp = () => icon(h('path', { d: 'M0 0v1h8v-1h-8zm4 3l-2 2h4l-2-2zm-4 3v2h8v-2h-8z' })); +export const iconCommand = () => icon(h('path', { d: 'M1.5 0c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5h.5v1h-.5c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5v-.5h1v.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5-.67-1.5-1.5-1.5h-.5v-1h.5c.83 0 1.5-.67 1.5-1.5s-.67-1.5-1.5-1.5-1.5.67-1.5 1.5v.5h-1v-.5c0-.83-.67-1.5-1.5-1.5zm0 1c.28 0 .5.22.5.5v.5h-.5c-.28 0-.5-.22-.5-.5s.22-.5.5-.5zm4 0c.28 0 .5.22.5.5s-.22.5-.5.5h-.5v-.5c0-.28.22-.5.5-.5zm-2.5 2h1v1h-1v-1zm-1.5 2h.5v.5c0 .28-.22.5-.5.5s-.5-.22-.5-.5.22-.5.5-.5zm3.5 0h.5c.28 0 .5.22.5.5s-.22.5-.5.5-.5-.22-.5-.5v-.5z' })); +export const iconCommentSquare = () => icon(h('path', { d: 'M.094 0c-.06 0-.094.034-.094.094v5.813c0 .06.034.094.094.094h5.906l2 2v-7.906c0-.06-.034-.094-.094-.094h-7.813z' })); +export const iconCompass = () => icon(h('path', { d: 'M4 0c-2.203 0-4 1.797-4 4 0 2.203 1.797 4 4 4 2.203 0 4-1.797 4-4 0-2.203-1.797-4-4-4zm0 1c1.663 0 3 1.337 3 3s-1.337 3-3 3-3-1.337-3-3 1.337-3 3-3zm2 1l-3 1-1 3 3-1 1-3zm-2 1.5c.28 0 .5.22.5.5s-.22.5-.5.5-.5-.22-.5-.5.22-.5.5-.5z' })); +export const iconContrast = () => icon(h('path', { d: 'M4 0c-2.203 0-4 1.797-4 4 0 2.203 1.797 4 4 4 2.203 0 4-1.797 4-4 0-2.203-1.797-4-4-4zm0 1c1.663 0 3 1.337 3 3s-1.337 3-3 3v-6z' })); +export const iconCopywriting = () => icon(h('path', { d: 'M0 0v1h8v-1h-8zm0 2v1h5v-1h-5zm0 3v1h8v-1h-8zm0 2v1h6v-1h-6zm7.5 0c-.276 0-.5.224-.5.5s.224.5.5.5.5-.224.5-.5-.224-.5-.5-.5z' })); +export const iconCreditCard = () => icon(h('path', { d: 'M.25 1c-.14 0-.25.11-.25.25v.75h8v-.75c0-.14-.11-.25-.25-.25h-7.5zm-.25 2v3.75c0 .14.11.25.25.25h7.5c.14 0 .25-.11.25-.25v-3.75h-8zm1 2h1v1h-1v-1zm2 0h1v1h-1v-1z' })); +export const iconCrop = () => icon(h('path', { d: 'M1 0v1h-1v1h1v5h5v1h1v-1h1v-1h-1v-4.5l1-1-.5-.5-1 1h-4.5v-1h-1zm1 2h3.5l-3.5 3.5v-3.5zm4 .5v3.5h-3.5l3.5-3.5z' })); +export const iconDashboard = () => icon(h('path', { d: 'M4 0c-2.203 0-4 1.797-4 4 0 2.203 1.797 4 4 4 2.203 0 4-1.797 4-4 0-2.203-1.797-4-4-4zm0 1c1.663 0 3 1.337 3 3s-1.337 3-3 3-3-1.337-3-3 1.337-3 3-3zm0 1c-.276 0-.5.224-.5.5s.224.5.5.5.5-.224.5-.5-.224-.5-.5-.5zm-1.656 1a.5.5 0 0 0-.188.844l.906.906-.063.25c0 .552.448 1 1 1s1-.448 1-1-.448-1-1-1l-.25.063-.906-.906a.5.5 0 0 0-.438-.156.5.5 0 0 0-.063 0zm3.156 0c-.276 0-.5.224-.5.5s.224.5.5.5.5-.224.5-.5-.224-.5-.5-.5z' })); +export const iconDataTransferDownload = () => icon(h('path', { d: 'M3 0v3h-2l3 3 3-3h-2v-3h-2zm-3 7v1h8v-1h-8z' })); +export const iconDataTransferUpload = () => icon(h('path', { d: 'M0 0v1h8v-1h-8zm4 2l-3 3h2v3h2v-3h2l-3-3z' })); +export const iconDelete = () => icon(h('path', { d: 'M2 1l-2 3 2 3h6v-6h-6zm1.5.781l1.5 1.5 1.5-1.5.719.719-1.5 1.5 1.5 1.5-.719.719-1.5-1.5-1.5 1.5-.719-.719 1.5-1.5-1.5-1.5.719-.719z' })); +export const iconDial = () => icon(h('path', { d: 'M4 1c-2.201 0-4 1.799-4 4h1c0-1.659 1.341-3 3-3s3 1.341 3 3h1c0-2.201-1.799-4-4-4zm-.594 2.094c-.82.25-1.406 1.006-1.406 1.906 0 1.1.9 2 2 2s2-.9 2-2c0-.9-.586-1.656-1.406-1.906l-.594.875-.594-.875z' })); +export const iconDocument = () => icon(h('path', { d: 'M0 0v8h7v-4h-4v-4h-3zm4 0v3h3l-3-3zm-3 2h1v1h-1v-1zm0 2h1v1h-1v-1zm0 2h4v1h-4v-1z' })); +export const iconDoubleQuoteSansLeft = () => icon(h('path', { d: 'M0 1v6l3-3v-3h-3zm5 0v6l3-3v-3h-3z' })); +export const iconDoubleQuoteSansRight = () => icon(h('path', { d: 'M3 1l-3 3v3h3v-6zm5 0l-3 3v3h3v-6z' })); +export const iconDoubleQuoteSerifLeft = () => icon(h('path', { d: 'M3 1c-1.651 0-3 1.349-3 3v3h3v-3h-2c0-1.109.891-2 2-2v-1zm5 0c-1.651 0-3 1.349-3 3v3h3v-3h-2c0-1.109.891-2 2-2v-1z' })); +export const iconDoubleQuoteSerifRight = () => icon(h('path', { d: 'M0 1v3h2c0 1.109-.891 2-2 2v1c1.651 0 3-1.349 3-3v-3h-3zm5 0v3h2c0 1.109-.891 2-2 2v1c1.651 0 3-1.349 3-3v-3h-3z' })); +export const iconDroplet = () => icon(h('path', { d: 'M4 0l-.344.344c-.11.11-2.656 2.685-2.656 4.875 0 1.65 1.35 3 3 3s3-1.35 3-3c0-2.19-2.546-4.765-2.656-4.875l-.344-.344zm-1.5 4.719c.28 0 .5.22.5.5 0 .55.45 1 1 1 .28 0 .5.22.5.5s-.22.5-.5.5c-1.1 0-2-.9-2-2 0-.28.22-.5.5-.5z' })); +export const iconEject = () => icon(h('path', { d: 'M4 0l-4 5h8l-4-5zm-4 6v2h8v-2h-8z' })); +export const iconElevator = () => icon(h('path', { d: 'M4 0l-3 3h6l-3-3zm-3 5l3 3 3-3h-6z' })); +export const iconEllipses = () => icon(h('path', { d: 'M0 3v2h2v-2h-2zm3 0v2h2v-2h-2zm3 0v2h2v-2h-2z' })); +export const iconEnvelopeClosed = () => icon(h('path', { d: 'M0 1v1l4 2 4-2v-1h-8zm0 2v4h8v-4l-4 2-4-2z' })); +export const iconEnvelopeOpen = () => icon(h('path', { d: 'M4 0l-4 2v6h8v-6l-4-2zm0 1.125l3 1.5v1.875l-3 1.5-3-1.5v-1.875l3-1.5zm-2 1.875v1l2 1 2-1v-1h-4z' })); +export const iconExcerpt = () => icon(h('path', { d: 'M0 0v1h7v-1h-7zm0 2v1h5v-1h-5zm0 2v1h8v-1h-8zm0 2v1h1v-1h-1zm2 0v1h1v-1h-1zm2 0v1h1v-1h-1z' })); +export const iconExpandDown = () => icon(h('path', { d: 'M0 0v1h8v-1h-8zm2 2l2 2 2-2h-4zm-2 4v2h8v-2h-8z' })); +export const iconExpandLeft = () => icon(h('path', { d: 'M0 0v8h1v-8h-1zm6 0v8h2v-8h-2zm-4 2v4l2-2-2-2z' })); +export const iconExpandRight = () => icon(h('path', { d: 'M0 0v8h2v-8h-2zm7 0v8h1v-8h-1zm-1 2l-2 2 2 2v-4z' })); +export const iconExpandUp = () => icon(h('path', { d: 'M0 0v2h8v-2h-8zm4 4l-2 2h4l-2-2zm-4 3v1h8v-1h-8z' })); +export const iconExternalLink = () => icon(h('path', { d: 'M0 0v8h8v-2h-1v1h-6v-6h1v-1h-2zm4 0l1.5 1.5-2.5 2.5 1 1 2.5-2.5 1.5 1.5v-4h-4z' })); +export const iconEye = () => icon(h('path', { d: 'M4.031 1c-2.53 0-4.031 3-4.031 3s1.501 3 4.031 3c2.47 0 3.969-3 3.969-3s-1.499-3-3.969-3zm-.031 1c1.1 0 2 .9 2 2s-.9 2-2 2-2-.9-2-2 .9-2 2-2zm0 1c-.55 0-1 .45-1 1s.45 1 1 1 1-.45 1-1c0-.1-.032-.191-.063-.281-.08.16-.237.281-.438.281-.28 0-.5-.22-.5-.5 0-.2.121-.357.281-.438-.09-.03-.181-.063-.281-.063z' })); +export const iconEyedropper = () => icon(h('path', { d: 'M3.313 0a.5.5 0 0 0-.188.844l.625.625-3.594 3.656-.156.156v2.719h2.719l.125-.156 3.656-3.656.625.656a.5.5 0 1 0 .719-.688l-.938-.938.656-.656c.59-.58.59-1.545 0-2.125-.56-.57-1.555-.57-2.125 0l-.656.656-.938-.938a.5.5 0 0 0-.469-.156.5.5 0 0 0-.063 0zm1.156 2.188l1.313 1.313-3.156 3.156-1.281-1.313 3.125-3.156z' })); +export const iconFile = () => icon(h('path', { d: 'M0 0v8h7v-4h-4v-4h-3zm4 0v3h3l-3-3z' })); +export const iconFire = () => icon(h('path', { d: 'M2 0c1 2-2 3-2 5l2 3c-.98-1.98 2-3 2-5l-2-3zm3 3c1 2-2 3-2 5h3c.4 0 1-.5 1-2 0-2-2-3-2-3z' })); +export const iconFlag = () => icon(h('path', { d: 'M0 0v8h1v-8h-1zm2 0v4h2v1h4l-2-1.969 2-2.031h-3v-1h-3z' })); +export const iconFlash = () => icon(h('path', { d: 'M3.5 0l-1.5 3h2l-.656 2h-1.344l1 3 3-3h-1.5l1.5-3h-2l1-2h-1.5z' })); +export const iconFolder = () => icon(h('path', { d: 'M0 0v2h8v-1h-5v-1h-3zm0 3v4.5c0 .28.22.5.5.5h7c.28 0 .5-.22.5-.5v-4.5h-8z' })); +export const iconFork = () => icon(h('path', { d: 'M1.5 0c-.828 0-1.5.672-1.5 1.5 0 .656.414 1.202 1 1.406v2.188c-.586.204-1 .75-1 1.406 0 .828.672 1.5 1.5 1.5s1.5-.672 1.5-1.5c0-.595-.341-1.101-.844-1.344.09-.09.205-.156.344-.156h2c.823 0 1.5-.677 1.5-1.5v-.594c.586-.204 1-.75 1-1.406 0-.828-.672-1.5-1.5-1.5s-1.5.672-1.5 1.5c0 .656.414 1.202 1 1.406v.594c0 .277-.223.5-.5.5h-2c-.171 0-.346.04-.5.094v-1.188c.586-.204 1-.75 1-1.406 0-.828-.672-1.5-1.5-1.5z' })); +export const iconFullscreenEnter = () => icon(h('path', { d: 'M0 0v4l1.5-1.5 1.5 1.5 1-1-1.5-1.5 1.5-1.5h-4zm5 4l-1 1 1.5 1.5-1.5 1.5h4v-4l-1.5 1.5-1.5-1.5z' })); +export const iconFullscreenExit = () => icon(h('path', { d: 'M1 0l-1 1 1.5 1.5-1.5 1.5h4v-4l-1.5 1.5-1.5-1.5zm3 4v4l1.5-1.5 1.5 1.5 1-1-1.5-1.5 1.5-1.5h-4z' })); +export const iconGlobe = () => icon(h('path', { d: 'M4 0c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm0 1c.333 0 .637.086.938.188-.214.197-.45.383-.406.563.04.18.688.13.688.5 0 .27-.425.346-.125.656.35.35-.636.978-.656 1.438-.03.83.841.969 1.531.969.424 0 .503.195.469.438-.546.758-1.438 1.25-2.438 1.25-.378 0-.729-.09-1.063-.219.224-.442-.313-1.344-.781-1.625-.226-.226-.689-.114-.969-.219-.092-.271-.178-.545-.188-.844.031-.05.081-.094.156-.094.19 0 .454.374.594.344.18-.04-.742-1.313-.313-1.563.2-.12.609.394.469-.156-.12-.51.366-.276.656-.406.26-.11.455-.414.125-.594l-.219-.188c.45-.27.972-.438 1.531-.438zm2.313 1.094c.184.222.323.481.438.75l-.188.219c-.29.27-.327-.212-.438-.313-.13-.11-.638.025-.688-.125-.077-.181.499-.418.875-.531z' })); +export const iconGraph = () => icon(h('path', { d: 'M7.031 0l-3.031 3-1-1-3 3.031 1 1 2-2.031 1 1 4-4-.969-1zm-7.031 7v1h8v-1h-8z' })); +export const iconGridFourUp = () => icon(h('path', { d: 'M0 0v1h1v-1h-1zm2 0v1h1v-1h-1zm2 0v1h1v-1h-1zm2 0v1h1v-1h-1zm-6 2v1h1v-1h-1zm2 0v1h1v-1h-1zm2 0v1h1v-1h-1zm2 0v1h1v-1h-1zm-6 2v1h1v-1h-1zm2 0v1h1v-1h-1zm2 0v1h1v-1h-1zm2 0v1h1v-1h-1zm-6 2v1h1v-1h-1zm2 0v1h1v-1h-1zm2 0v1h1v-1h-1zm2 0v1h1v-1h-1z' })); +export const iconGridThreeUp = () => icon(h('path', { d: 'M0 0v2h2v-2h-2zm3 0v2h2v-2h-2zm3 0v2h2v-2h-2zm-6 3v2h2v-2h-2zm3 0v2h2v-2h-2zm3 0v2h2v-2h-2zm-6 3v2h2v-2h-2zm3 0v2h2v-2h-2zm3 0v2h2v-2h-2z' })); +export const iconGridTwoUp = () => icon(h('path', { d: 'M0 0v3h3v-3h-3zm5 0v3h3v-3h-3zm-5 5v3h3v-3h-3zm5 0v3h3v-3h-3z' })); +export const iconHardDrive = () => icon(h('path', { d: 'M.188 0c-.11 0-.188.077-.188.188v3.313c0 .28.22.5.5.5h6c.28 0 .5-.22.5-.5v-3.313c0-.11-.077-.188-.188-.188h-6.625zm-.188 4.906v2.906c0 .11.077.188.188.188h6.625c.11 0 .188-.077.188-.188v-2.906c-.16.05-.32.094-.5.094h-6c-.18 0-.34-.044-.5-.094zm5.5 1.094c.28 0 .5.22.5.5s-.22.5-.5.5-.5-.22-.5-.5.22-.5.5-.5z' })); +export const iconHeader = () => icon(h('path', { d: 'M0 0v1h.5c.28 0 .5.22.5.5v4c0 .28-.22.5-.5.5h-.5v1h3v-1h-.5c-.28 0-.5-.22-.5-.5v-1.5h3v1.5c0 .28-.22.5-.5.5h-.5v1h3v-1h-.5c-.28 0-.5-.22-.5-.5v-4c0-.28.22-.5.5-.5h.5v-1h-3v1h.5c.28 0 .5.22.5.5v1.5h-3v-1.5c0-.28.22-.5.5-.5h.5v-1h-3z' })); +export const iconHeadphones = () => icon(h('path', { d: 'M4 0c-1.651 0-3 1.349-3 3v1h-.5a.5.5 0 0 0-.5.5v2a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-3.5c0-1.109.891-2 2-2s2 .891 2 2v3.5a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-2a.5.5 0 0 0-.5-.5h-.5v-1c0-1.651-1.349-3-3-3z' })); +export const iconHeart = () => icon(h('path', { d: 'M2 1c-.55 0-1.046.224-1.406.594-.37.36-.594.856-.594 1.406 0 .55.224 1.046.594 1.406l3.406 3.438 3.406-3.438c.37-.37.594-.856.594-1.406 0-.55-.224-1.046-.594-1.406-.36-.37-.856-.594-1.406-.594-.55 0-1.046.224-1.406.594-.37.36-.594.856-.594 1.406 0-.55-.224-1.046-.594-1.406-.36-.37-.856-.594-1.406-.594z' })); +export const iconHome = () => icon(h('path', { d: 'M4 0l-4 3h1v4h2v-2h2v2h2v-4.031l1 .031-4-3z' })); +export const imagE = () => icon(h('path', { d: 'M0 0v8h8v-8h-8zm1 1h6v3l-1-1-1 1 2 2v1h-1l-4-4-1 1v-3z' })); +export const inboX = () => icon(h('path', { d: 'M.188 0c-.11 0-.188.077-.188.188v7.625c0 .11.077.188.188.188h7.625c.11 0 .188-.077.188-.188v-7.625c0-.11-.077-.188-.188-.188h-7.625zm.813 2h6v3h-1l-1 1h-2l-1-1h-1v-3z' })); +export const infiNity = () => icon(h('path', { d: 'M2 2c-1.31 0-2 1.01-2 2s.69 2 2 2c.79 0 1.42-.559 2-1.219.58.66 1.19 1.219 2 1.219 1.31 0 2-1.01 2-2s-.69-2-2-2c-.81 0-1.42.559-2 1.219-.57-.66-1.21-1.219-2-1.219zm0 1c.42 0 .884.47 1.344 1-.46.53-.924 1-1.344 1-.74 0-1-.54-1-1 0-.46.26-1 1-1zm4 0c.74 0 1 .54 1 1 0 .46-.26 1-1 1-.43 0-.894-.47-1.344-1 .45-.53.914-1 1.344-1z' })); +export const info = () => icon(h('path', { d: 'M5 0c-.552 0-1 .448-1 1s.448 1 1 1 1-.448 1-1-.448-1-1-1zm-1.5 2.5c-.83 0-1.5.67-1.5 1.5h1c0-.28.22-.5.5-.5s.5.22.5.5-1 1.64-1 2.5c0 .86.67 1.5 1.5 1.5s1.5-.67 1.5-1.5h-1c0 .28-.22.5-.5.5s-.5-.22-.5-.5c0-.36 1-1.84 1-2.5 0-.81-.67-1.5-1.5-1.5z' })); +export const italIc = () => icon(h('path', { d: 'M2 0v1h1.625l-.063.125-2 5-.344.875h-1.219v1h5v-1h-1.625l.063-.125 2-5 .344-.875h1.219v-1h-5z' })); +export const iconJustifyCenter = () => icon(h('path', { d: 'M0 0v1h8v-1h-8zm0 2v1h8v-1h-8zm0 2v1h8v-1h-8zm1 2v1h6v-1h-6z' })); +export const iconJustifyLeft = () => icon(h('path', { d: 'M0 0v1h8v-1h-8zm0 2v1h8v-1h-8zm0 2v1h8v-1h-8zm0 2v1h6v-1h-6z' })); +export const iconJustifyRight = () => icon(h('path', { d: 'M0 0v1h8v-1h-8zm0 2v1h8v-1h-8zm0 2v1h8v-1h-8zm2 2v1h6v-1h-6z' })); +export const iconKey = () => icon(h('path', { d: 'M5.5 0c-1.38 0-2.5 1.12-2.5 2.5 0 .16.033.297.063.438l-3.063 3.063v2h3v-2h2v-1l.063-.063c.14.03.277.063.438.063 1.38 0 2.5-1.12 2.5-2.5s-1.12-2.5-2.5-2.5zm.5 1c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1z' })); +export const iconLaptop = () => icon(h('path', { d: 'M1.344 0a.5.5 0 0 0-.344.5v3.5h-1v1.5c0 .28.22.5.5.5h7c.28 0 .5-.22.5-.5v-1.5h-1v-3.5a.5.5 0 0 0-.5-.5h-5a.5.5 0 0 0-.094 0 .5.5 0 0 0-.063 0zm.656 1h4v3h-1v1h-2v-1h-1v-3z' })); +export const iconLayers = () => icon(h('path', { d: 'M0 0v4h4v-4h-4zm5 2v3h-3v1h4v-4h-1zm2 2v3h-3v1h4v-4h-1z' })); +export const iconLinkBroken = () => icon(h('path', { d: 'M2 0v1h-1v1h2v-2h-1zm3.875.031c-.184.01-.354.03-.531.094-.27.095-.531.25-.75.469l-.438.438a.5.5 0 1 0 .688.688l.438-.438c.101-.101.245-.173.375-.219.352-.126.78-.064 1.063.219.395.389.4 1.037 0 1.438l-1.5 1.5a.5.5 0 1 0 .688.688l1.5-1.5c.78-.78.785-2.041 0-2.813-.279-.279-.606-.452-.969-.531-.181-.039-.379-.041-.563-.031zm-3.594 2.906a.5.5 0 0 0-.188.156l-1.5 1.5c-.78.78-.785 2.041 0 2.813.557.557 1.355.722 2.063.469.27-.095.531-.25.75-.469l.438-.438a.5.5 0 1 0-.688-.688l-.438.438c-.101.101-.245.173-.375.219-.352.126-.78.064-1.063-.219-.395-.389-.4-1.037 0-1.438l1.5-1.5a.5.5 0 0 0-.438-.844.5.5 0 0 0-.063 0zm2.719 3.063v2h1v-1h1v-1h-2z' })); +export const iconLinkIntact = () => icon(h('path', { d: 'M5.875.031c-.184.01-.354.03-.531.094-.27.095-.531.25-.75.469a.5.5 0 1 0 .688.688c.101-.101.245-.173.375-.219.352-.126.78-.064 1.063.219.395.389.4 1.037 0 1.438l-1.5 1.5c-.434.434-.799.483-1.063.469-.264-.015-.406-.125-.406-.125a.504.504 0 1 0-.5.875s.34.222.844.25c.504.028 1.197-.165 1.813-.781l1.5-1.5c.78-.78.785-2.041 0-2.813-.279-.279-.606-.452-.969-.531-.181-.039-.379-.041-.563-.031zm-2 2.313c-.501-.019-1.186.155-1.781.75l-1.5 1.5c-.78.78-.785 2.041 0 2.813.557.557 1.355.722 2.063.469.27-.095.531-.25.75-.469a.5.5 0 1 0-.688-.688c-.101.101-.245.173-.375.219-.352.126-.78.064-1.063-.219-.395-.389-.4-1.037 0-1.438l1.5-1.5c.405-.405.752-.448 1.031-.438.279.011.469.094.469.094a.5.5 0 1 0 .438-.875s-.343-.199-.844-.219z' })); +export const iconListRich = () => icon(h('path', { d: 'M0 0v3h3v-3h-3zm4 0v1h4v-1h-4zm0 2v1h3v-1h-3zm-4 2v3h3v-3h-3zm4 0v1h4v-1h-4zm0 2v1h3v-1h-3z' })); +export const iconList = () => icon(h('path', { d: 'M.5 0c-.276 0-.5.224-.5.5s.224.5.5.5.5-.224.5-.5-.224-.5-.5-.5zm1.5 0v1h6v-1h-6zm-1.5 2c-.276 0-.5.224-.5.5s.224.5.5.5.5-.224.5-.5-.224-.5-.5-.5zm1.5 0v1h6v-1h-6zm-1.5 2c-.276 0-.5.224-.5.5s.224.5.5.5.5-.224.5-.5-.224-.5-.5-.5zm1.5 0v1h6v-1h-6zm-1.5 2c-.276 0-.5.224-.5.5s.224.5.5.5.5-.224.5-.5-.224-.5-.5-.5zm1.5 0v1h6v-1h-6z' })); +export const iconLocation = () => icon(h('path', { d: 'M8 0l-8 4 3 1 1 3 4-8z' })); +export const iconLockLocked = (className) => icon(h('path', { d: 'M4 0c-1.099 0-2 .901-2 2v1h-1v4h6v-4h-1v-1c0-1.099-.901-2-2-2zm0 1c.561 0 1 .439 1 1v1h-2v-1c0-.561.439-1 1-1z' }), className); +export const iconLockUnlocked = () => icon(h('path', { d: 'M4 0c-1.099 0-2 .901-2 2h1c0-.561.439-1 1-1 .561 0 1 .439 1 1v2h-4v4h6v-4h-1v-2c0-1.099-.901-2-2-2z' })); +export const iconLoopCircular = () => icon(h('path', { d: 'M4 1c-1.651 0-3 1.349-3 3h-1l1.5 2 1.5-2h-1c0-1.109.891-2 2-2v-1zm2.5 1l-1.5 2h1c0 1.109-.891 2-2 2v1c1.651 0 3-1.349 3-3h1l-1.5-2z' })); +export const iconLoopSquare = () => icon(h('path', { d: 'M1 0v2h1v-1h4v2h-1l1.5 2.5 1.5-2.5h-1v-3h-6zm.5 2.5l-1.5 2.5h1v3h6v-2h-1v1h-4v-2h1l-1.5-2.5z' })); +export const iconLoop = () => icon(h('path', { d: 'M6 0v1h-5c-.554 0-1 .446-1 1v1h1v-1h5v1l2-1.5-2-1.5zm-4 4l-2 1.5 2 1.5v-1h5c.542 0 1-.458 1-1v-1h-1v1h-5v-1z' })); +export const iconMagnifyingGlass = () => icon(h('path', { d: 'M3.5 0c-1.927 0-3.5 1.573-3.5 3.5s1.573 3.5 3.5 3.5c.592 0 1.166-.145 1.656-.406a1 1 0 0 0 .125.125l1 1a1.016 1.016 0 1 0 1.438-1.438l-1-1a1 1 0 0 0-.156-.125c.266-.493.438-1.059.438-1.656 0-1.927-1.573-3.5-3.5-3.5zm0 1c1.387 0 2.5 1.113 2.5 2.5 0 .661-.241 1.273-.656 1.719l-.031.031a1 1 0 0 0-.125.125c-.442.397-1.043.625-1.688.625-1.387 0-2.5-1.113-2.5-2.5s1.113-2.5 2.5-2.5z' })); +export const iconMapMarker = () => icon(h('path', { d: 'M4 0c-1.66 0-3 1.34-3 3 0 2 3 5 3 5s3-3 3-5c0-1.66-1.34-3-3-3zm0 1c1.1 0 2 .9 2 2s-.9 2-2 2-2-.9-2-2 .9-2 2-2z' })); +export const iconMap = () => icon(h('path', { d: 'M0 0v8h8v-2.375a.5.5 0 0 0 0-.219v-5.406h-8zm1 1h6v4h-1.5a.5.5 0 0 0-.094 0 .502.502 0 1 0 .094 1h1.5v1h-6v-6zm2.5 1c-.83 0-1.5.67-1.5 1.5 0 1 1.5 2.5 1.5 2.5s1.5-1.5 1.5-2.5c0-.83-.67-1.5-1.5-1.5zm0 1c.28 0 .5.22.5.5s-.22.5-.5.5-.5-.22-.5-.5.22-.5.5-.5z' })); +export const iconMediaPause = () => icon(h('path', { d: 'M1 1v6h2v-6h-2zm4 0v6h2v-6h-2z' })); +export const iconMediaPlay = () => icon(h('path', { d: 'M1 1v6l6-3-6-3z' })); +export const iconMediaRecord = () => icon(h('path', { d: 'M4 1c-1.657 0-3 1.343-3 3s1.343 3 3 3 3-1.343 3-3-1.343-3-3-3z' })); +export const iconMediaSkipBackward = () => icon(h('path', { d: 'M4 1l-4 3 4 3v-6zm0 3l4 3v-6l-4 3z' })); +export const iconMediaSkipForward = () => icon(h('path', { d: 'M0 1v6l4-3-4-3zm4 3v3l4-3-4-3v3z' })); +export const iconMediaStepBackward = () => icon(h('path', { d: 'M0 1v6h2v-6h-2zm2 3l5 3v-6l-5 3z' })); +export const iconMediaStepForward = () => icon(h('path', { d: 'M0 1v6l5-3-5-3zm5 3v3h2v-6h-2v3z' })); +export const iconMediaStop = () => icon(h('path', { d: 'M1 1v6h6v-6h-6z' })); +export const iconMedicalCross = () => icon(h('path', { d: 'M2 0v2h-2v4h2v2h4v-2h2v-4h-2v-2h-4z' })); +export const iconMenu = () => icon(h('path', { d: 'M0 1v1h8v-1h-8zm0 2.969v1h8v-1h-8zm0 3v1h8v-1h-8z' })); +export const iconMicrophone = () => icon(h('path', { d: 'M2.906-.031a1 1 0 0 0-.125.031 1 1 0 0 0-.781 1v2a1 1 0 1 0 2 0v-2a1 1 0 0 0-1.094-1.031zm-2.563 2.031a.5.5 0 0 0-.344.5v.5c0 1.476 1.091 2.693 2.5 2.938v1.063h-.5c-.55 0-1 .45-1 1h4c0-.55-.45-1-1-1h-.5v-1.063c1.409-.244 2.5-1.461 2.5-2.938v-.5a.5.5 0 1 0-1 0v.5c0 1.109-.891 2-2 2s-2-.891-2-2v-.5a.5.5 0 0 0-.594-.5.5.5 0 0 0-.063 0z' })); +export const iconMinus = () => icon(h('path', { d: 'M0 3v2h8v-2h-8z' })); +export const iconMonitor = () => icon(h('path', { d: 'M.344 0a.5.5 0 0 0-.344.5v5a.5.5 0 0 0 .5.5h2.5v1h-1c-.55 0-1 .45-1 1h6c0-.55-.45-1-1-1h-1v-1h2.5a.5.5 0 0 0 .5-.5v-5a.5.5 0 0 0-.5-.5h-7a.5.5 0 0 0-.094 0 .5.5 0 0 0-.063 0zm.656 1h6v4h-6v-4z' })); +export const iconMoon = () => icon(h('path', { d: 'M2.719 0c-1.58.53-2.719 2.021-2.719 3.781 0 2.21 1.79 4 4 4 1.76 0 3.251-1.17 3.781-2.75-.4.14-.831.25-1.281.25-2.21 0-4-1.79-4-4 0-.44.079-.881.219-1.281z' })); +export const iconMove = () => icon(h('path', { d: 'M3.5 0l-1.5 1.5h1v1.5h-1.5v-1l-1.5 1.5 1.5 1.5v-1h1.5v1.5h-1l1.5 1.5 1.5-1.5h-1v-1.5h1.5v1l1.5-1.5-1.5-1.5v1h-1.5v-1.5h1l-1.5-1.5z' })); +export const iconMusicalNote = () => icon(h('path', { d: 'M8 0c-5 0-6 1-6 1v4.094c-.154-.054-.327-.094-.5-.094-.828 0-1.5.672-1.5 1.5s.672 1.5 1.5 1.5 1.5-.672 1.5-1.5v-3.969c.732-.226 1.99-.438 4-.5v2.063c-.154-.054-.327-.094-.5-.094-.828 0-1.5.672-1.5 1.5s.672 1.5 1.5 1.5 1.5-.672 1.5-1.5v-5.5z' })); +export const iconPaperclip = () => icon(h('path', { d: 'M5 0c-.514 0-1.021.201-1.406.594l-2.781 2.719c-1.07 1.07-1.07 2.805 0 3.875 1.07 1.07 2.805 1.07 3.875 0l1.25-1.25-.688-.688-.906.875-.344.375c-.69.69-1.81.69-2.5 0-.682-.682-.668-1.778 0-2.469l2.781-2.719v-.031c.389-.395 1.037-.4 1.438 0 .388.381.378 1.006 0 1.406l-2.5 2.469c-.095.095-.28.095-.375 0-.095-.095-.095-.28 0-.375l.375-.344.594-.625-.688-.688-.875.875-.094.094c-.485.485-.485 1.265 0 1.75.485.485 1.265.485 1.75 0l2.5-2.438c.78-.78.785-2.041 0-2.813-.39-.39-.893-.594-1.406-.594z' })); +export const iconPencil = () => icon(h('path', { d: 'M6 0l-1 1 2 2 1-1-2-2zm-2 2l-4 4v2h2l4-4-2-2z' })); +export const iconPeople = () => icon(h('path', { d: 'M5.5 0c-.51 0-.949.355-1.219.875.45.54.719 1.275.719 2.125 0 .29-.034.574-.094.844.18.11.374.156.594.156.83 0 1.5-.9 1.5-2s-.67-2-1.5-2zm-3 1c-.828 0-1.5.895-1.5 2s.672 2 1.5 2 1.5-.895 1.5-2-.672-2-1.5-2zm4.75 3.156c-.43.51-1.018.824-1.688.844.27.38.438.844.438 1.344v.656h2v-1.656c0-.52-.31-.968-.75-1.188zm-6.5 1c-.44.22-.75.668-.75 1.188v1.656h5v-1.656c0-.52-.31-.968-.75-1.188-.44.53-1.06.844-1.75.844s-1.31-.314-1.75-.844z' })); +export const iconPerson = () => icon(h('path', { d: 'M4 0c-1.105 0-2 1.119-2 2.5s.895 2.5 2 2.5 2-1.119 2-2.5-.895-2.5-2-2.5zm-2.094 5c-1.07.04-1.906.92-1.906 2v1h8v-1c0-1.08-.836-1.96-1.906-2-.54.61-1.284 1-2.094 1-.81 0-1.554-.39-2.094-1z' })); +export const iconPhone = () => icon(h('path', { d: 'M1.188 0c-.11 0-.188.077-.188.188v7.625c0 .11.077.188.188.188h4.625c.11 0 .188-.077.188-.188v-7.625c0-.11-.077-.188-.188-.188h-4.625zm.813 1h3v5h-3v-5zm1.5 5.5c.28 0 .5.22.5.5s-.22.5-.5.5-.5-.22-.5-.5.22-.5.5-.5z' })); +export const iconPieChart = () => icon(h('path', { d: 'M3.5 0c-.97 0-1.839.391-2.469 1.031l2.969 2.969v-3.969c-.16-.03-.33-.031-.5-.031zm1.5 1.063v3.406l-2.719 2.719c.6.5 1.369.813 2.219.813 1.93 0 3.5-1.57 3.5-3.5 0-1.76-1.31-3.197-3-3.438zm-4.094 1.313c-.55.54-.906 1.285-.906 2.125 0 .95.435 1.804 1.125 2.344l2.156-2.125-2.375-2.344z' })); +export const iconPin = () => icon(h('path', { d: 'M1.344 0a.502.502 0 0 0 .156 1h.5v2h-1c-.55 0-1 .45-1 1h3v3l.438 1 .563-1v-3h3c0-.55-.45-1-1-1h-1v-2h.5a.5.5 0 1 0 0-1h-4a.5.5 0 0 0-.094 0 .502.502 0 0 0-.063 0z' })); +export const iconPlayCircle = () => icon(h('path', { d: 'M4 0c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm-1 2l3 2-3 2v-4z' })); +export const iconPlus = () => icon(h('path', { d: 'M3 0v3h-3v2h3v3h2v-3h3v-2h-3v-3h-2z' })); +export const iconPowerStandby = () => icon(h('path', { d: 'M3 0v4h1v-4h-1zm-1.281 1.438l-.375.313c-.803.64-1.344 1.634-1.344 2.75 0 1.929 1.571 3.5 3.5 3.5s3.5-1.571 3.5-3.5c0-1.116-.529-2.11-1.344-2.75l-.375-.313-.625.781.375.313c.585.46.969 1.165.969 1.969 0 1.391-1.109 2.5-2.5 2.5s-2.5-1.109-2.5-2.5c0-.804.361-1.509.938-1.969l.406-.313-.625-.781z' })); +export const iconPrint = () => icon(h('path', { d: 'M2 0v2h4v-2h-4zm-1.906 3c-.06 0-.094.034-.094.094v2.813c0 .06.034.094.094.094h.906v-2h6v2h.906c.06 0 .094-.034.094-.094v-2.813c0-.06-.034-.094-.094-.094h-7.813zm1.906 2v3h4v-3h-4z' })); +export const iconProject = () => icon(h('path', { d: 'M0 0v7h1v-7h-1zm7 0v7h1v-7h-1zm-5 1v1h2v-1h-2zm1 2v1h2v-1h-2zm1 2v1h2v-1h-2z' })); +export const iconPulse = () => icon(h('path', { d: 'M3.25 0l-.469 1.531-.781 2.563-.031-.063-.094-.344h-1.875v1h1.156l.375 1.156.469 1.469.469-1.469.781-2.5.781 2.5.406 1.313.531-1.281.594-1.469.125.281h2.313v-1h-1.688l-.375-.719-.5-1-.406 1.031-.469 1.188-.844-2.656-.469-1.531z' })); +export const iconPuzzlePiece = () => icon(h('path', { d: 'M3 0c-.28 0-.539.101-.719.281-.18.18-.281.439-.281.719 0 .28.181.479.281.719.03.06.063.161.063.281h-2.344v6h2.344c0-.12-.011-.221-.031-.281-.11-.24-.313-.439-.313-.719 0-.28.101-.539.281-.719.18-.18.439-.281.719-.281.28 0 .539.101.719.281.18.18.281.439.281.719 0 .28-.181.479-.281.719-.03.06-.063.161-.063.281h2.344v-2.344c.12 0 .221.011.281.031.24.11.439.313.719.313.28 0 .539-.101.719-.281.18-.18.281-.439.281-.719 0-.28-.101-.539-.281-.719-.18-.18-.439-.281-.719-.281-.28 0-.479.181-.719.281-.06.03-.161.063-.281.063v-2.344h-2.344c0-.12.011-.221.031-.281.11-.24.313-.439.313-.719 0-.28-.101-.539-.281-.719-.18-.18-.439-.281-.719-.281z' })); +export const iconRandom = () => icon(h('path', { d: 'M6 0v1h-.5c-.354 0-.6.116-.813.375l-1.406 1.75-1.5-1.75v-.031c-.212-.236-.427-.344-.781-.344h-1v1h1.031v.031l1.625 1.906-1.625 2.031v.031h-1.031v1h1c.354 0 .6-.116.813-.375l1.531-1.906 1.625 1.906v.031c.212.236.427.344.781.344h.25v1l2-1.5-2-1.5v1h-.281v-.031l-1.75-2.063 1.5-1.875v-.031h.531v1l2-1.5-2-1.5z' })); +export const iconReload = () => icon(h('path', { d: 'M4 0c-2.201 0-4 1.799-4 4s1.799 4 4 4c1.104 0 2.092-.456 2.813-1.188l-.688-.688c-.54.548-1.289.875-2.125.875-1.659 0-3-1.341-3-3s1.341-3 3-3c.834 0 1.545.354 2.094.906l-1.094 1.094h3v-3l-1.188 1.188c-.731-.72-1.719-1.188-2.813-1.188z' })); +export const iconResizeBoth = () => icon(h('path', { d: 'M4 0l1.656 1.656-4 4-1.656-1.656v4h4l-1.656-1.656 4-4 1.656 1.656v-4h-4z' })); +export const iconResizeHeight = () => icon(h('path', { d: 'M3.5 0l-2.5 3h2v2h-2l2.5 3 2.5-3h-2v-2h2l-2.5-3z' })); +export const iconResizeWidth = () => icon(h('path', { d: 'M3 1l-3 2.5 3 2.5v-2h2v2l3-2.5-3-2.5v2h-2v-2z' })); +export const iconRssAlt = () => icon(h('path', { d: 'M0 0v2c3.331 0 6 2.669 6 6h2c0-4.409-3.591-8-8-8zm0 3v2c1.67 0 3 1.33 3 3h2c0-2.75-2.25-5-5-5zm0 3v2h2c0-1.11-.89-2-2-2z' })); +export const iconRss = () => icon(h('path', { d: 'M1 0v1c3.32 0 6 2.68 6 6h1c0-3.86-3.14-7-7-7zm0 2v1c2.221 0 4 1.779 4 4h1c0-2.759-2.241-5-5-5zm0 2v1c1.109 0 2 .891 2 2h1c0-1.651-1.349-3-3-3zm0 2c-.552 0-1 .448-1 1s.448 1 1 1 1-.448 1-1-.448-1-1-1z' })); +export const iconScript = () => icon(h('path', { d: 'M3 0c-.55 0-1 .45-1 1v5.5c0 .28-.22.5-.5.5s-.5-.22-.5-.5v-1.5h-1v2c0 .55.45 1 1 1h5c.55 0 1-.45 1-1v-3h-4v-2.5c0-.28.22-.5.5-.5s.5.22.5.5v1.5h4v-2c0-.55-.45-1-1-1h-4z' })); +export const iconShareBoxed = () => icon(h('path', { d: 'M.75 0c-.402 0-.75.348-.75.75v5.5c0 .402.348.75.75.75h4.5c.402 0 .75-.348.75-.75v-1.25h-1v1h-4v-5h2v-1h-2.25zm5.25 0v1c-2.05 0-3.704 1.544-3.938 3.531.213-.875.999-1.531 1.938-1.531h2v1l2-2-2-2z' })); +export const iconShare = () => icon(h('path', { d: 'M5 0v2c-4 0-5 2.05-5 5 .52-1.98 2-3 4-3h1v2l3-3.156-3-2.844z' })); +export const iconShield = () => icon(h('path', { d: 'M4 0l-.188.094-3.5 1.469-.313.125v.313c0 1.657.666 3.122 1.469 4.188.401.533.828.969 1.25 1.281.422.313.826.531 1.281.531.455 0 .86-.219 1.281-.531.422-.313.849-.749 1.25-1.281.803-1.065 1.469-2.53 1.469-4.188v-.313l-.313-.125-3.5-1.469-.188-.094zm0 1.094v5.906c-.045 0-.328-.069-.656-.313s-.714-.631-1.063-1.094c-.642-.851-1.137-2.025-1.219-3.281l2.938-1.219z' })); +export const iconSignal = () => icon(h('path', { d: 'M6 0v8h1v-8h-1zm-2 1v7h1v-7h-1zm-2 2v5h1v-5h-1zm-2 2v3h1v-3h-1z' })); +export const iconSignpost = () => icon(h('path', { d: 'M3 0v1h-2l-1 1 1 1h2v5h1v-4h2l1-1-1-1h-2v-2h-1z' })); +export const iconSortAscending = () => icon(h('path', { d: 'M2 0v6h-2l2.5 2 2.5-2h-2v-6h-1zm2 0v1h2v-1h-2zm0 2v1h3v-1h-3zm0 2v1h4v-1h-4z' })); +export const iconSortDescending = () => icon(h('path', { d: 'M2 0v6h-2l2.5 2 2.5-2h-2v-6h-1zm2 0v1h4v-1h-4zm0 2v1h3v-1h-3zm0 2v1h2v-1h-2z' })); +export const iconSpreadsheet = () => icon(h('path', { d: 'M.75 0c-.402 0-.75.348-.75.75v5.5c0 .402.348.75.75.75h6.5c.402 0 .75-.348.75-.75v-5.5c0-.402-.348-.75-.75-.75h-6.5zm.25 1h1v1h-1v-1zm2 0h4v1h-4v-1zm-2 2h1v1h-1v-1zm2 0h4v1h-4v-1zm-2 2h1v1h-1v-1zm2 0h4v1h-4v-1z' })); +export const iconStar = () => icon(h('path', { d: 'M4 0l-1 3h-3l2.5 2-1 3 2.5-2 2.5 2-1-3 2.5-2h-3l-1-3z' })); +export const iconSun = () => icon(h('path', { d: 'M4 0c-.276 0-.5.224-.5.5s.224.5.5.5.5-.224.5-.5-.224-.5-.5-.5zm-2.5 1c-.276 0-.5.224-.5.5s.224.5.5.5.5-.224.5-.5-.224-.5-.5-.5zm5 0c-.276 0-.5.224-.5.5s.224.5.5.5.5-.224.5-.5-.224-.5-.5-.5zm-2.5 1c-1.105 0-2 .895-2 2s.895 2 2 2 2-.895 2-2-.895-2-2-2zm-3.5 1.5c-.276 0-.5.224-.5.5s.224.5.5.5.5-.224.5-.5-.224-.5-.5-.5zm7 0c-.276 0-.5.224-.5.5s.224.5.5.5.5-.224.5-.5-.224-.5-.5-.5zm-6 2.5c-.276 0-.5.224-.5.5s.224.5.5.5.5-.224.5-.5-.224-.5-.5-.5zm5 0c-.276 0-.5.224-.5.5s.224.5.5.5.5-.224.5-.5-.224-.5-.5-.5zm-2.5 1c-.276 0-.5.224-.5.5s.224.5.5.5.5-.224.5-.5-.224-.5-.5-.5z' })); +export const iconTablet = () => icon(h('path', { d: 'M.344 0c-.18 0-.344.164-.344.344v7.313c0 .18.164.344.344.344h6.313c.18 0 .344-.164.344-.344v-7.313c0-.18-.164-.344-.344-.344h-6.313zm.656 1h5v5h-5v-5zm2.5 5.5c.28 0 .5.22.5.5s-.22.5-.5.5-.5-.22-.5-.5.22-.5.5-.5z' })); +export const iconTag = () => icon(h('path', { d: 'M0 0v3l5 5 3-3-5-5h-3zm2 1c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1z' })); +export const iconTags = () => icon(h('path', { d: 'M0 1v2l3 3 1.5-1.5.5-.5-2-2-1-1h-2zm3.406 0l3 3-1.188 1.219.781.781 2-2-3-3h-1.594zm-1.906 1c.28 0 .5.22.5.5s-.22.5-.5.5-.5-.22-.5-.5.22-.5.5-.5z' })); +export const iconTarget = () => icon(h('path', { d: 'M4 0c-2.203 0-4 1.797-4 4 0 2.203 1.797 4 4 4 2.203 0 4-1.797 4-4 0-2.203-1.797-4-4-4zm0 1c1.663 0 3 1.337 3 3s-1.337 3-3 3-3-1.337-3-3 1.337-3 3-3zm0 1c-1.099 0-2 .901-2 2s.901 2 2 2 2-.901 2-2-.901-2-2-2zm0 1c.558 0 1 .442 1 1s-.442 1-1 1-1-.442-1-1 .442-1 1-1z' })); +export const iconTask = () => icon(h('path', { d: 'M0 0v7h7v-3.594l-1 1v1.594h-5v-5h3.594l1-1h-5.594zm7 0l-3 3-1-1-1 1 2 2 4-4-1-1z' })); +export const iconTerminal = () => icon(h('path', { d: 'M.094 0c-.06 0-.094.034-.094.094v7.813c0 .06.034.094.094.094h7.813c.06 0 .094-.034.094-.094v-7.813c0-.06-.034-.094-.094-.094h-7.813zm1.406.781l1.719 1.719-1.719 1.719-.719-.719 1-1-1-1 .719-.719zm2.5 2.219h3v1h-3v-1z' })); +export const iconText = () => icon(h('path', { d: 'M0 0v2h.5c0-.55.45-1 1-1h1.5v5.5c0 .28-.22.5-.5.5h-.5v1h4v-1h-.5c-.28 0-.5-.22-.5-.5v-5.5h1.5c.55 0 1 .45 1 1h.5v-2h-8z' })); +export const iconThumbDown = () => icon(h('path', { d: 'M0 0v4h1v-4h-1zm2 0v4.001c.28 0 .529.101.719.281.18.19 1.151 2.115 1.281 2.375.13.26.386.393.656.313.26-.08.393-.355.313-.625-.08-.26-.469-1.594-.469-1.844s.22-.5.5-.5h1.5c.28 0 .5-.22.5-.5l-1.031-3.188c-.08-.18-.259-.313-.469-.313h-3.5z' })); +export const iconThumbUp = () => icon(h('path', { d: 'M4.438 0c-.19.021-.34.149-.438.344-.13.26-1.101 2.185-1.281 2.375-.19.18-.439.281-.719.281v4.001h3.5c.21 0 .389-.133.469-.313 0 0 1.031-2.908 1.031-3.188 0-.28-.22-.5-.5-.5h-1.5c-.28 0-.5-.25-.5-.5s.389-1.574.469-1.844c.08-.27-.053-.545-.313-.625l-.219-.031zm-4.438 3v4h1v-4h-1z' })); +export const iconTimer = () => icon(h('path', { d: 'M2 0v1h1v.031c-1.697.241-3 1.707-3 3.469 0 1.929 1.571 3.5 3.5 3.5s3.5-1.571 3.5-3.5c0-.45-.086-.874-.219-1.25l-.938.344c.107.304.156.596.156.906 0 1.391-1.109 2.5-2.5 2.5s-2.5-1.109-2.5-2.5 1.109-2.5 2.5-2.5c.298 0 .585.051.875.156l.344-.938c-.221-.081-.471-.119-.719-.156v-.063h1v-1h-3zm5 1.125s-3.675 2.8-3.875 3c-.2.2-.2.519 0 .719.2.2.519.2.719 0 .2-.19 3.156-3.719 3.156-3.719z' })); +export const iconTransfer = () => icon(h('path', { d: 'M6 0v1h-6v1h6v1l2-1.5-2-1.5zm-4 4l-2 1.5 2 1.5v-1h6v-1h-6v-1z' })); +export const iconTrash = () => icon(h('path', { d: 'M3 0c-.55 0-1 .45-1 1h-1c-.55 0-1 .45-1 1h7c0-.55-.45-1-1-1h-1c0-.55-.45-1-1-1h-1zm-2 3v4.813c0 .11.077.188.188.188h4.625c.11 0 .188-.077.188-.188v-4.813h-1v3.5c0 .28-.22.5-.5.5s-.5-.22-.5-.5v-3.5h-1v3.5c0 .28-.22.5-.5.5s-.5-.22-.5-.5v-3.5h-1z' })); +export const iconUnderline = () => icon(h('path', { d: 'M1 0v4c0 1.1 1.12 2 2.5 2h.5c1.1 0 2-.9 2-2v-4h-1v4c0 .55-.45 1-1 1s-1-.45-1-1v-4h-2zm-1 7v1h7v-1h-7z' })); +export const iconVerticalAlignBottom = () => icon(h('path', { d: 'M.094 0c-.06 0-.094.034-.094.094v4.813c0 .06.034.094.094.094h1.813c.06 0 .094-.034.094-.094v-4.813c0-.06-.034-.094-.094-.094h-1.813zm6 0c-.06 0-.094.034-.094.094v4.813c0 .06.034.094.094.094h1.813c.06 0 .094-.034.094-.094v-4.813c0-.06-.034-.094-.094-.094h-1.813zm-3 2c-.06 0-.094.034-.094.094v2.813c0 .06.034.094.094.094h1.813c.06 0 .094-.034.094-.094v-2.813c0-.06-.034-.094-.094-.094h-1.813zm-3.094 4v1h8v-1h-8z' })); +export const iconVerticalAlignCenter = () => icon(h('path', { d: 'M.094 0c-.06 0-.094.034-.094.094v1.906h2v-1.906c0-.06-.034-.094-.094-.094h-1.813zm6 0c-.06 0-.094.034-.094.094v1.906h2v-1.906c0-.06-.034-.094-.094-.094h-1.813zm-3 1c-.06 0-.094.034-.094.094v.906h2v-.906c0-.06-.034-.094-.094-.094h-1.813zm-3.094 2v1h8v-1h-8zm0 2v1.906c0 .06.034.094.094.094h1.813c.06 0 .094-.034.094-.094v-1.906h-2zm3 0v.906c0 .06.034.094.094.094h1.813c.06 0 .094-.034.094-.094v-.906h-2zm3 0v1.906c0 .06.034.094.094.094h1.813c.06 0 .094-.034.094-.094v-1.906h-2z' })); +export const iconVerticalAlignTop = () => icon(h('path', { d: 'M0 0v1h8v-1h-8zm.094 2c-.06 0-.094.034-.094.094v4.813c0 .06.034.094.094.094h1.813c.06 0 .094-.034.094-.094v-4.813c0-.06-.034-.094-.094-.094h-1.813zm3 0c-.06 0-.094.034-.094.094v2.813c0 .06.034.094.094.094h1.813c.06 0 .094-.034.094-.094v-2.813c0-.06-.034-.094-.094-.094h-1.813zm3 0c-.06 0-.094.034-.094.094v4.813c0 .06.034.094.094.094h1.813c.06 0 .094-.034.094-.094v-4.813c0-.06-.034-.094-.094-.094h-1.813z' })); +export const iconVideo = () => icon(h('path', { d: 'M.5 1c-.28 0-.5.22-.5.5v4c0 .28.22.5.5.5h5c.28 0 .5-.22.5-.5v-1.5l1 1h1v-3h-1l-1 1v-1.5c0-.28-.22-.5-.5-.5h-5z' })); +export const iconVolumeHigh = () => icon(h('path', { d: 'M3.344 0l-1.344 2h-2v4h2l1.344 2h.656v-8h-.656zm1.656 1v1c.152 0 .313.026.469.063h.031c.86.215 1.5.995 1.5 1.938 0 .942-.64 1.722-1.5 1.938-.166.041-.338.063-.5.063v1c.258 0 .516-.035.75-.094 1.3-.325 2.25-1.508 2.25-2.906 0-1.398-.95-2.581-2.25-2.906-.234-.059-.492-.094-.75-.094zm0 2v2l.25-.031c.433-.118.75-.507.75-.969 0-.446-.325-.819-.75-.938v-.031h-.031l-.219-.031z' })); +export const iconVolumeLow = () => icon(h('path', { d: 'M4.344 0l-1.344 2h-2v4h2l1.344 2h.656v-8h-.656zm1.656 3v2l.25-.031c.433-.118.75-.507.75-.969 0-.446-.325-.819-.75-.938v-.031h-.031l-.219-.031z' })); +export const iconVolumeOff = () => icon(h('path', { d: 'M5.344 0l-1.344 2h-2v4h2l1.344 2h.656v-8h-.656z' })); +export const iconWarning = () => icon(h('path', { d: 'M3.094 0c-.06 0-.105.044-.125.094l-2.938 6.813-.031.188v.813c0 .06.034.094.094.094h6.813c.06 0 .094-.034.094-.094v-.813l-.031-.188-2.938-6.813c-.02-.05-.065-.094-.125-.094h-.813zm-.094 3h1v2h-1v-2zm0 3h1v1h-1v-1z' })); +export const iconWifi = () => icon(h('path', { d: 'M3.75 0c-1.374 0-2.66.372-3.75 1.063l.531.875c.93-.59 2.033-.938 3.219-.938 1.2 0 2.323.31 3.25.906l.531-.813c-1.093-.703-2.401-1.094-3.781-1.094zm.031 3c-.795 0-1.531.227-2.156.625l.531.844c.475-.302 1.02-.469 1.625-.469.593 0 1.13.177 1.594.469l.531-.844c-.616-.388-1.338-.625-2.125-.625zm-.031 3c-.552 0-1 .448-1 1s.448 1 1 1 1-.448 1-1-.448-1-1-1z' })); +export const iconWrench = () => icon(h('path', { d: 'M5.5 0c-1.38 0-2.5 1.12-2.5 2.5 0 .32.078.626.188.906l-2.906 2.875c-.39.39-.39 1.016 0 1.406.2.2.459.313.719.313.26 0 .519-.091.719-.281l2.875-2.875c.28.1.586.156.906.156 1.38 0 2.5-1.12 2.5-2.5 0-.16-.032-.297-.063-.438l-.938.938h-2v-2l.938-.938c-.14-.03-.277-.062-.438-.063zm-4.5 6.5c.28 0 .5.22.5.5s-.22.5-.5.5-.5-.22-.5-.5.22-.5.5-.5z' })); +export const iconX = () => icon(h('path', { d: 'M1.406 0l-1.406 1.406.688.719 1.781 1.781-1.781 1.781-.688.719 1.406 1.406.719-.688 1.781-1.781 1.781 1.781.719.688 1.406-1.406-.688-.719-1.781-1.781 1.781-1.781.688-.719-1.406-1.406-.719.688-1.781 1.781-1.781-1.781-.719-.688z' })); +export const iconZoomIn = () => icon(h('path', { d: 'M3.5 0c-1.927 0-3.5 1.573-3.5 3.5s1.573 3.5 3.5 3.5c.592 0 1.166-.145 1.656-.406a1 1 0 0 0 .094.094l1.031 1.031a1.016 1.016 0 1 0 1.438-1.438l-1.031-1.031a1 1 0 0 0-.125-.094c.266-.493.438-1.059.438-1.656 0-1.927-1.573-3.5-3.5-3.5zm0 1c1.387 0 2.5 1.113 2.5 2.5 0 .587-.196 1.137-.531 1.563l-.031.031a1 1 0 0 0-.063.031 1 1 0 0 0-.281.281 1 1 0 0 0-.063.063c-.422.326-.953.531-1.531.531-1.387 0-2.5-1.113-2.5-2.5s1.113-2.5 2.5-2.5zm-.5 1v1h-1v1h1v1h1v-1h1v-1h-1v-1h-1z' })); +export const iconZoomOut = () => icon(h('path', { d: 'M3.5 0c-1.927 0-3.5 1.573-3.5 3.5s1.573 3.5 3.5 3.5c.592 0 1.166-.145 1.656-.406a1 1 0 0 0 .094.094l1.031 1.031a1.016 1.016 0 1 0 1.438-1.438l-1.031-1.031a1 1 0 0 0-.125-.094c.266-.493.438-1.059.438-1.656 0-1.927-1.573-3.5-3.5-3.5zm0 1c1.387 0 2.5 1.113 2.5 2.5 0 .587-.196 1.137-.531 1.563l-.031.031a1 1 0 0 0-.063.031 1 1 0 0 0-.281.281 1 1 0 0 0-.063.063c-.422.326-.953.531-1.531.531-1.387 0-2.5-1.113-2.5-2.5s1.113-2.5 2.5-2.5zm-1.5 2v1h3v-1h-3z' })); diff --git a/Framework/Frontend/js/src/index.js b/Framework/Frontend/js/src/index.js index f72b3fe2a..7a9a88a14 100644 --- a/Framework/Frontend/js/src/index.js +++ b/Framework/Frontend/js/src/index.js @@ -10,31 +10,31 @@ * In applying this license CERN does not waive the privileges and immunities * granted to it by virtue of its status as an Intergovernmental Organization * or submit itself to any jurisdiction. -*/ + */ // Design patterns -export {default as Observable} from './Observable.js'; -export {default as EventEmitter} from './EventEmitter.js'; -export {RemoteData} from './RemoteData.js'; +export { default as Observable } from './Observable.js'; +export { default as EventEmitter } from './EventEmitter.js'; +export { RemoteData } from './RemoteData.js'; // Template engine -export {render, h, frameDebouncer, mount} from './renderer.js'; -export {default as QueryRouter} from './QueryRouter.js'; +export { render, h, frameDebouncer, mount } from './renderer.js'; +export { default as QueryRouter } from './QueryRouter.js'; // Utils -export {default as switchCase} from './switchCase.js'; +export { default as switchCase } from './switchCase.js'; // Formatters -export {formatTimeDuration} from "./formatter/formatTimeDuration.js"; +export { formatTimeDuration } from './formatter/formatTimeDuration.js'; // Singleton retrieving session data -export {default as sessionService} from './sessionService.js'; +export { default as sessionService } from './sessionService.js'; // Data sources -export {default as fetchClient} from './fetchClient.js'; -export {default as WebSocketClient} from './WebSocketClient.js'; -export {default as Loader} from './Loader.js'; -export {default as BrowserStorage} from './BrowserStorage.js'; +export { default as fetchClient } from './fetchClient.js'; +export { default as WebSocketClient } from './WebSocketClient.js'; +export { default as Loader } from './Loader.js'; +export { default as BrowserStorage } from './BrowserStorage.js'; // All icons helpers, namespaced with prefix 'icon*' export * from './icons.js'; diff --git a/Framework/Frontend/js/src/renderer.js b/Framework/Frontend/js/src/renderer.js index 7553c5f3e..fdb526c03 100644 --- a/Framework/Frontend/js/src/renderer.js +++ b/Framework/Frontend/js/src/renderer.js @@ -10,15 +10,19 @@ * In applying this license CERN does not waive the privileges and immunities * granted to it by virtue of its status as an Intergovernmental Organization * or submit itself to any jurisdiction. -*/ + */ /** * Template engine functions using vnode and DOM diff algo * @module renderer */ -// mithril function 'm' will be injected into window -// it is used by renderer as an abstracted engine +/* eslint-disable @stylistic/js/max-len */ + +/* + * Mithril function 'm' will be injected into window + * it is used by renderer as an abstracted engine + */ import '/mithril/mithril.min.js'; if (!window.m) { @@ -36,11 +40,11 @@ if (!window.requestAnimationFrame) { */ function frameDebouncer(fn) { let requestFrame; - return function(...args) { + return function (...args) { if (requestFrame) { window.cancelAnimationFrame(requestFrame); } - requestFrame = window.requestAnimationFrame(function() { + requestFrame = window.requestAnimationFrame(() => { fn(...args); }); }; @@ -56,7 +60,7 @@ function frameDebouncer(fn) { * render(document.body, virtualNode); */ function render(element, vnode) { - // encapsulate mithril engine so we can change if needed + // Encapsulate mithril engine so we can change if needed window.m.render(element, vnode); } @@ -77,19 +81,20 @@ function render(element, vnode) { * Hyperscript function to represente a DOM element * it produces a vnode usable by render function. * - * @param {String} selector - Tag name (div, p, h1...) and optional classes as CSS selector (.foo.bar.baz), empty string =~ 'div' - * @param {Object} attributes - (optional) Properties and attributes of DOM elements and hooks (see description). Here is a non-exhaustive list of common uses: - * @param {string} attributes.className - Additional class names - * @param {function} attributes.onclick - On mouse click [DOM handler onclick](https://developer.mozilla.org/fr/docs/Web/API/GlobalEventHandlers/onclick) - * @param {function} attributes.oninput - On content typed inside input tag [DOM handler oninput](https://developer.mozilla.org/fr/docs/Web/API/GlobalEventHandlers/oninput) - * @param {string|Object} attributes.style - `style: "background:red;"` or `style: {background: "red"}` - * @param {string} attributes.href - Destination for links [DOM href property](https://developer.mozilla.org/en-US/docs/Web/API/HTMLHyperlinkElementUtils/href) - * @param {string} attributes.placeholder - Placeholder for inputs [DOM input, all properties](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input) - * @param {string} attributes.value - Value for inputs [DOM input, all properties](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input) - * @param {Hook} attributes.oncreate - Hook called after a DOM element is created and attached to the document - * @param {Hook} attributes.onupdate - Hook is called after each render, while DOM element is attached to the document - * @param {Hook} attributes.onremove - Hook is called before a DOM element is removed from the document - * @param {Array.|string} children - Children inside this tag + * @param {...any} args - arguments to be passes as below + * @param {String} args.selector - Tag name (div, p, h1...) and optional classes as CSS selector (.foo.bar.baz), empty string =~ 'div' + * @param {Object} args.attributes - (optional) Properties and attributes of DOM elements and hooks (see description). Here is a non-exhaustive list of common uses: + * @param {string} args.attributes.className - Additional class names + * @param {function} args.attributes.onclick - On mouse click [DOM handler onclick](https://developer.mozilla.org/fr/docs/Web/API/GlobalEventHandlers/onclick) + * @param {function} args.attributes.oninput - On content typed inside input tag [DOM handler oninput](https://developer.mozilla.org/fr/docs/Web/API/GlobalEventHandlers/oninput) + * @param {string|Object} args.attributes.style - `style: "background:red;"` or `style: {background: "red"}` + * @param {string} args.attributes.href - Destination for links [DOM href property](https://developer.mozilla.org/en-US/docs/Web/API/HTMLHyperlinkElementUtils/href) + * @param {string} args.attributes.placeholder - Placeholder for inputs [DOM input, all properties](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input) + * @param {string} args.attributes.value - Value for inputs [DOM input, all properties](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input) + * @param {Hook} args.attributes.oncreate - Hook called after a DOM element is created and attached to the document + * @param {Hook} args.attributes.onupdate - Hook is called after each render, while DOM element is attached to the document + * @param {Hook} args.attributes.onremove - Hook is called before a DOM element is removed from the document + * @param {Array.|string} args.children - Children inside this tag * @return {vnode} the vnode representation * @example Simple tag declaration * import {h, render} from '/js/src/index.js'; @@ -113,7 +118,7 @@ function render(element, vnode) { * render(document.body, containerNode); */ function h(...args) { - // encapsulate mithril engine so we can change if needed + // Encapsulate mithril engine so we can change if needed return window.m(...args); } @@ -139,7 +144,7 @@ function mount(element, view, model, debug) { console.time('render'); } try { - render(element, (typeof view === "function" ? view : view.view)(model)); + render(element, (typeof view === 'function' ? view : view.view)(model)); } finally { if (debug) { // eslint-disable-next-line no-console @@ -149,9 +154,9 @@ function mount(element, view, model, debug) { }); if (model.observe) { - model.observe(smartRender); // redraw on changes + model.observe(smartRender); // Redraw on changes } - render(element, (typeof view === "function" ? view : view.view)(model)); // first draw + render(element, (typeof view === 'function' ? view : view.view)(model)); // First draw } -export {h, render, frameDebouncer, mount}; +export { h, render, frameDebouncer, mount }; diff --git a/Framework/Frontend/js/src/sessionService.js b/Framework/Frontend/js/src/sessionService.js index 6bf79a5d1..310f40ccc 100644 --- a/Framework/Frontend/js/src/sessionService.js +++ b/Framework/Frontend/js/src/sessionService.js @@ -12,13 +12,15 @@ * or submit itself to any jurisdiction. */ -/* global: window */ +/* Global: window */ -const location = window.location; -const history = window.history; +const { location } = window; +const { history } = window; -// These are the parameters coming from the server only and represent -// the current session +/* + * These are the parameters coming from the server only and represent + * the current session + */ const parametersNames = ['personid', 'name', 'token', 'username', 'access']; /** @@ -67,8 +69,7 @@ export class SessionService { _hideParameters() { const url = new URL(location); parametersNames.forEach((parameterName) => - url.searchParams.delete(parameterName), - ); + url.searchParams.delete(parameterName)); history.replaceState({}, '', url); } @@ -91,7 +92,7 @@ export class SessionService { * @return {boolean} true if the user has one of the given roles, else false */ hasAccess(roles) { - const {access} = this.get(); + const { access } = this.get(); return access.some((userRole) => roles.includes(userRole)); } diff --git a/Framework/Frontend/js/src/switchCase.js b/Framework/Frontend/js/src/switchCase.js index 17289bd60..aeece23ea 100644 --- a/Framework/Frontend/js/src/switchCase.js +++ b/Framework/Frontend/js/src/switchCase.js @@ -10,13 +10,13 @@ * In applying this license CERN does not waive the privileges and immunities * granted to it by virtue of its status as an Intergovernmental Organization * or submit itself to any jurisdiction. -*/ + */ /** * Functional switch case - * @param {string} caseName - * @param {Object.} cases - * @param {Any} defaultCaseValue + * @param {string} caseName - the caseName to be compared + * @param {Object.} cases - the cases to be compared + * @param {Any} defaultCaseValue - the default caseValue * @return {Any} the corresponding caseValue of the caseName * @example * import {h, switchCase} from '/js/src/index.js'; @@ -30,6 +30,6 @@ * ]); */ const switchCase = (caseName, cases, defaultCaseValue) => - cases.hasOwnProperty(caseName) ? cases[caseName] : defaultCaseValue; + Object.prototype.hasOwnProperty.call(cases, caseName) ? cases[caseName] : defaultCaseValue; export default switchCase; diff --git a/Framework/Frontend/js/src/utilities/durationUtils.js b/Framework/Frontend/js/src/utilities/durationUtils.js index a5b320cd1..b8360774a 100644 --- a/Framework/Frontend/js/src/utilities/durationUtils.js +++ b/Framework/Frontend/js/src/utilities/durationUtils.js @@ -29,5 +29,5 @@ export const splitDuration = (duration) => { const minutes = Math.floor(duration % MILLISECONDS_IN_ONE_HOUR / MILLISECONDS_IN_ONE_MINUTE); const seconds = Math.floor(duration % MILLISECONDS_IN_ONE_MINUTE / MILLISECONDS_IN_ONE_SECOND); - return {hours, minutes, seconds}; + return { hours, minutes, seconds }; }; diff --git a/Framework/Frontend/test/index-test.js b/Framework/Frontend/test/index-test.js index e50de0aad..6251fda07 100644 --- a/Framework/Frontend/test/index-test.js +++ b/Framework/Frontend/test/index-test.js @@ -10,15 +10,16 @@ * In applying this license CERN does not waive the privileges and immunities * granted to it by virtue of its status as an Intergovernmental Organization * or submit itself to any jurisdiction. -*/ - + */ const HttpServer = require('../../Backend/http/server.js'); const path = require('path'); -// Reading config file -// Start servers -const http = new HttpServer({hostname: 'localhost', port: 8085}, {}); +/* + * Reading config file + * Start servers + */ +const http = new HttpServer({ hostname: 'localhost', port: 8085 }, {}); http.addStaticPath(path.join(__dirname, 'public')); http.post('/ok.json', replyWithOk); @@ -26,12 +27,12 @@ http.get('/ok.json', replyWithOk); /** * Reply for API calls - * @param {Request} req - * @param {Response} res + * @param {Request} req - HTTP request object + * @param {Response} res - HTTP response object */ function replyWithOk(req, res) { res.set({ - 'Content-type': 'application/json' + 'Content-type': 'application/json', }); - res.status(200).json({ok: req.method}); + res.status(200).json({ ok: req.method }); } diff --git a/Framework/Frontend/test/mocha-index.js b/Framework/Frontend/test/mocha-index.js index 9970f49bf..3286ec25f 100644 --- a/Framework/Frontend/test/mocha-index.js +++ b/Framework/Frontend/test/mocha-index.js @@ -10,7 +10,7 @@ * In applying this license CERN does not waive the privileges and immunities * granted to it by virtue of its status as an Intergovernmental Organization * or submit itself to any jurisdiction. -*/ + */ /* eslint-disable */ diff --git a/Framework/docs/tutorial/config.js b/Framework/docs/tutorial/config.js index cfd268fbb..0be99471a 100644 --- a/Framework/docs/tutorial/config.js +++ b/Framework/docs/tutorial/config.js @@ -10,19 +10,21 @@ * In applying this license CERN does not waive the privileges and immunities * granted to it by virtue of its status as an Intergovernmental Organization * or submit itself to any jurisdiction. -*/ + */ -// This is quick start configuration -// See the Backend documentation for more details -// +/* + * This is quick start configuration + * See the Backend documentation for more details + * + */ module.exports = { jwt: { secret: 'supersecret', - expiration: '10m' + expiration: '10m', }, http: { port: 8080, hostname: 'localhost', - tls: false - } + tls: false, + }, }; diff --git a/Framework/docs/tutorial/index.js b/Framework/docs/tutorial/index.js index c831bc8ba..76264ecdb 100644 --- a/Framework/docs/tutorial/index.js +++ b/Framework/docs/tutorial/index.js @@ -10,10 +10,10 @@ * In applying this license CERN does not waive the privileges and immunities * granted to it by virtue of its status as an Intergovernmental Organization * or submit itself to any jurisdiction. -*/ + */ // Import the backend classes -const {HttpServer, LogManager, WebSocket, WebSocketMessage} = require('@aliceo2/web-ui'); +const { HttpServer, LogManager, WebSocket, WebSocketMessage } = require('@aliceo2/web-ui'); // Define configuration for JWT tokens and HTTP server const config = require('./config.js'); @@ -21,10 +21,12 @@ const config = require('./config.js'); // Get logger instance const logger = LogManager.getLogger('Tutorial'); -// HTTP server -// ----------- -// -// Instanciate the HTTP server +/* + * HTTP server + * ----------- + * + * Instantiate the HTTP server + */ const httpServer = new HttpServer(config.http, config.jwt); // Server static content in public directory @@ -32,14 +34,15 @@ httpServer.addStaticPath('./public'); // Declare HTTP POST route availabe under "/api/getDate" path httpServer.post('/getDate', (req, res) => { - res.json({date: new Date()}); + res.json({ date: new Date() }); }); - -// WebSocket server -// ---------------- -// -// Instanciate the WebSocket server +/* + * WebSocket server + * ---------------- + * + * Instantiate the WebSocket server + */ const wsServer = new WebSocket(httpServer); // Define gloval variable @@ -48,7 +51,7 @@ let streamTimer = null; // Declare WebSocket callback for 'stream-date' messages wsServer.bind('stream-date', () => { if (streamTimer) { - // already started, kill it + // Already started, kill it clearInterval(streamTimer); streamTimer = null; return; @@ -59,9 +62,7 @@ wsServer.bind('stream-date', () => { // Broadcase the time to all clients every 100ms streamTimer = setInterval(() => { - wsServer.broadcast( - new WebSocketMessage().setCommand('server-date').setPayload({date: new Date()}) - ); + wsServer.broadcast(new WebSocketMessage().setCommand('server-date').setPayload({ date: new Date() })); }, 100); return new WebSocketMessage().setCommand('stream-date'); }); diff --git a/Framework/eslint.config.js b/Framework/eslint.config.js new file mode 100644 index 000000000..0d2382b21 --- /dev/null +++ b/Framework/eslint.config.js @@ -0,0 +1,305 @@ +/** + * @license + * Copyright 2019-2020 CERN and copyright holders of ALICE O2. + * See http://alice-o2.web.cern.ch/copyright for details of the copyright holders. + * All rights not expressly granted are reserved. + * + * This software is distributed under the terms of the GNU General Public + * License v3 (GPL Version 3), copied verbatim in the file "COPYING". + * + * In applying this license CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization + * or submit itself to any jurisdiction. + */ + +const globals = require('globals'); +const pluginJs = require('@eslint/js'); +const jsdoc = require('eslint-plugin-jsdoc'); +const stylisticJs = require('@stylistic/eslint-plugin-js'); + +module.exports = [ + { + ignores: [ + 'node_modules/', + 'database/data/', + 'lib/public/assets/', + 'cpp-api-client/', + 'tmp/', + '.nyc_output/', + ], + }, + jsdoc.configs['flat/recommended'], + pluginJs.configs.recommended, + { + plugins: { + jsdoc, + '@stylistic/js': stylisticJs, + }, + languageOptions: { + parserOptions: { + sourceType: 'module', + }, + globals: { + ...globals.browser, + ...globals.node, + ...globals.mocha, + process: 'readonly', + Model: 'readonly', + vnode: 'readonly', + Express: 'readonly', + setImmediate: 'readonly', + }, + }, + settings: { + jsdoc: { + tagNamePreference: { + returns: 'return', + }, + }, + }, + rules: { + 'arrow-body-style': ['error', 'as-needed'], + curly: 'error', + 'init-declarations': 'off', + 'no-console': 'error', + 'no-implicit-coercion': 'error', + 'no-return-assign': 'error', + 'no-unused-vars': [ + 'error', + { + argsIgnorePattern: '^(_|((request|response|next)$))', + }, + ], + 'no-var': 'error', + 'one-var': [ + 'error', + 'never', + ], + 'prefer-arrow-callback': [ + 'error', + { + allowUnboundThis: true, + }, + ], + 'prefer-const': 'error', + 'prefer-destructuring': 'error', + 'prefer-object-spread': 'error', + 'prefer-template': 'error', + radix: 'error', + 'capitalized-comments': [ + 'error', + 'always', + ], + 'jsdoc/require-description': ['error'], + 'jsdoc/require-returns': [0], // TODO + 'jsdoc/require-jsdoc': [ + 'error', + { + require: { + FunctionDeclaration: true, + MethodDefinition: true, + ClassDeclaration: true, + ArrowFunctionExpression: false, // TODO + FunctionExpression: true, + }, + }, + ], + 'jsdoc/check-tag-names': ['off'], // TODO + 'jsdoc/check-values': ['off'], + 'jsdoc/check-types': ['off'], // TODO + 'jsdoc/require-property-description': ['off'], // TODO + 'jsdoc/no-multi-asterisks': ['off'], + 'jsdoc/no-undefined-types': ['off'], + 'jsdoc/no-defaults': ['off'], + // 'jsdoc/tag-lines': ['error', 'any', { startLines: 1 }], + 'jsdoc/tag-lines': ['off'], // TODO with above 0 or 1 + '@stylistic/js/array-bracket-newline': [ + 'error', + { + multiline: true, + }, + ], + '@stylistic/js/array-bracket-spacing': [ + 'error', + 'never', + { + singleValue: false, + }, + ], + '@stylistic/js/array-element-newline': [ + 'error', + 'consistent', + ], + '@stylistic/js/arrow-parens': [ + 'error', + 'always', + ], + '@stylistic/js/brace-style': [ + 'error', + '1tbs', + { + allowSingleLine: false, + }, + ], + '@stylistic/js/comma-dangle': [ + 'error', + 'always-multiline', + ], + '@stylistic/js/comma-spacing': [ + 'error', + { + before: false, + after: true, + }, + ], + '@stylistic/js/comma-style': [ + 'error', + 'last', + ], + '@stylistic/js/computed-property-spacing': 'error', + '@stylistic/js/dot-location': [ + 'error', + 'property', + ], + '@stylistic/js/eol-last': [ + 'error', + 'always', + ], + '@stylistic/js/function-call-argument-newline': [ + 'error', + 'consistent', + ], + '@stylistic/js/function-paren-newline': [ + 'error', + 'multiline', + ], + '@stylistic/js/indent': [ + 'error', + 2, + { + SwitchCase: 1, + }, + ], + '@stylistic/js/key-spacing': 'error', + '@stylistic/js/keyword-spacing': 'error', + '@stylistic/js/linebreak-style': 'off', + '@stylistic/js/lines-around-comment': [ + 'error', + { + allowBlockStart: true, + allowClassStart: true, + beforeBlockComment: true, + }, + ], + '@stylistic/js/lines-between-class-members': [ + 'error', + 'always', + ], + '@stylistic/js/max-len': [ + 'error', + { + code: 145, + }, + ], + '@stylistic/js/multiline-comment-style': [ + 'error', + 'starred-block', + ], + '@stylistic/js/no-extra-parens': [ + 'error', + 'all', + { + conditionalAssign: false, + ternaryOperandBinaryExpressions: false, + }, + ], + '@stylistic/js/no-multi-spaces': 'error', + '@stylistic/js/no-multiple-empty-lines': [ + 'error', + { + max: 1, + maxBOF: 0, + maxEOF: 0, + }, + ], + '@stylistic/js/no-trailing-spaces': 'error', + '@stylistic/js/object-curly-spacing': [ + 'error', + 'always', + ], + '@stylistic/js/object-property-newline': [ + 'error', + { + allowAllPropertiesOnSameLine: true, + }, + ], + '@stylistic/js/padded-blocks': [ + 'error', + 'never', + ], + '@stylistic/js/padding-line-between-statements': [ + 'error', + { + blankLine: 'always', + prev: 'cjs-import', + next: '*', + }, + { + blankLine: 'any', + prev: 'cjs-import', + next: 'cjs-import', + }, + { + blankLine: 'always', + prev: '*', + next: 'cjs-export', + }, + ], + '@stylistic/js/quote-props': [ + 'error', + 'as-needed', + ], + '@stylistic/js/quotes': [ + 'error', + 'single', + { + avoidEscape: true, + }, + ], + '@stylistic/js/semi': 'error', + '@stylistic/js/semi-style': [ + 'error', + 'last', + ], + '@stylistic/js/space-before-blocks': [ + 'error', + { + functions: 'always', + keywords: 'always', + classes: 'always', + }, + ], + '@stylistic/js/space-before-function-paren': [ + 'error', + { + anonymous: 'always', + named: 'never', + asyncArrow: 'always', + }, + ], + '@stylistic/js/space-infix-ops': 'error', + '@stylistic/js/space-in-parens': [ + 'error', + 'never', + ], + '@stylistic/js/template-curly-spacing': [ + 'error', + 'never', + ], + 'no-magic-numbers': 'off', // TODO: enable + 'sort-keys': 'off', + 'sort-imports': 'off', + 'sort-vars': 'off', + }, + }, +]; diff --git a/Framework/package-lock.json b/Framework/package-lock.json index b04c3fdd8..23ff6b2cf 100644 --- a/Framework/package-lock.json +++ b/Framework/package-lock.json @@ -20,7 +20,11 @@ "ws": "^8.18.0" }, "devDependencies": { - "eslint": "^8.57.0", + "@eslint/js": "^9.7.0", + "@stylistic/eslint-plugin-js": "^2.3.0", + "eslint": "^9.7.0", + "eslint-plugin-jsdoc": "^48.7.0", + "globals": "^15.8.0", "mocha": "^10.7.0", "nock": "13.5.0", "nyc": "^17.0.0", @@ -484,6 +488,20 @@ "kuler": "^2.0.0" } }, + "node_modules/@es-joy/jsdoccomment": { + "version": "0.46.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.46.0.tgz", + "integrity": "sha512-C3Axuq1xd/9VqFZpW4YAzOx5O9q/LP46uIQy/iNDpHG3fmPa6TBtvfglMCs3RBiBxAIi0Go97r8+jvTt55XMyQ==", + "dev": true, + "dependencies": { + "comment-parser": "1.4.1", + "esquery": "^1.6.0", + "jsdoc-type-pratt-parser": "~4.0.0" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.3.0.tgz", @@ -500,24 +518,38 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.6.2.tgz", - "integrity": "sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==", + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", + "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, + "node_modules/@eslint/config-array": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.17.1.tgz", + "integrity": "sha512-BlYOpej8AQ8Ev9xVqroV7a02JK3SkBAaN9GfMMH9W6Ch8FlQlkjGw4Ir7+FgYwfirivAf4t+GtzuAxqfukmISA==", + "dev": true, + "dependencies": { + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", + "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", + "espree": "^10.0.1", + "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -525,33 +557,40 @@ "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "version": "9.7.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.7.0.tgz", + "integrity": "sha512-ChuWDQenef8OSFnvuxv0TCVxEwmu3+hPNKvM9B34qpM0rDRbjL8t5QkQeHHeAfsKQjuH9wS82WeCi1J/owatng==", "dev": true, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "node_modules/@eslint/object-schema": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", + "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, "engines": { - "node": ">=10.10.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@humanwhocodes/module-importer": { @@ -567,11 +606,18 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", - "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", - "dev": true + "node_modules/@humanwhocodes/retry": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", + "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", @@ -764,6 +810,18 @@ "node": ">= 8" } }, + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, "node_modules/@puppeteer/browsers": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.2.3.tgz", @@ -871,12 +929,64 @@ "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", "dev": true }, + "node_modules/@stylistic/eslint-plugin-js": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-2.3.0.tgz", + "integrity": "sha512-lQwoiYb0Fs6Yc5QS3uT8+T9CPKK2Eoxc3H8EnYJgM26v/DgtW+1lvy2WNgyBflU+ThShZaHm3a6CdD9QeKx23w==", + "dev": true, + "dependencies": { + "@types/eslint": "^8.56.10", + "acorn": "^8.11.3", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.0.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/@stylistic/eslint-plugin-js/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@tootallnate/quickjs-emscripten": { "version": "0.23.0", "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", "dev": true }, + "node_modules/@types/eslint": { + "version": "8.56.11", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.11.tgz", + "integrity": "sha512-sVBpJMf7UPo/wGecYOpk2aQya2VUGeHhe38WG7/mN5FufNSubf5VT9Uh9Uyp8/eLJpu1/tuhJ/qTo4mhSB4V4Q==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, "node_modules/@types/node": { "version": "20.14.10", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz", @@ -902,12 +1012,6 @@ "@types/node": "*" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -921,9 +1025,9 @@ } }, "node_modules/acorn": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", - "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -1046,6 +1150,15 @@ "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", "dev": true }, + "node_modules/are-docs-informative": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", + "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", + "dev": true, + "engines": { + "node": ">=14" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -1555,6 +1668,15 @@ "node": ">= 0.8" } }, + "node_modules/comment-parser": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", + "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", + "dev": true, + "engines": { + "node": ">= 12.0.0" + } + }, "node_modules/commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -1786,18 +1908,6 @@ "node": ">=0.3.1" } }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/ecdsa-sig-formatter": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", @@ -1863,6 +1973,12 @@ "is-arrayish": "^0.2.1" } }, + "node_modules/es-module-lexer": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", + "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", + "dev": true + }, "node_modules/es6-error": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", @@ -1917,41 +2033,37 @@ } }, "node_modules/eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "version": "9.7.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.7.0.tgz", + "integrity": "sha512-FzJ9D/0nGiCGBf8UXO/IGLTgLVzIxze1zpfA8Ton2mjLovXdAPlYDv+MQDcqj3TmrhAGYfOpz9RfR+ent0AgAw==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", + "@eslint-community/regexpp": "^4.11.0", + "@eslint/config-array": "^0.17.0", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.7.0", "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.3.0", "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", - "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", + "eslint-scope": "^8.0.2", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.1.0", + "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", + "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", @@ -1965,23 +2077,76 @@ "eslint": "bin/eslint.js" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://eslint.org/donate" + } + }, + "node_modules/eslint-plugin-jsdoc": { + "version": "48.8.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.8.3.tgz", + "integrity": "sha512-AtIvwwW9D17MRkM0Z0y3/xZYaa9mdAvJrkY6fU/HNUwGbmMtHVvK4qRM9CDixGVtfNrQitb8c6zQtdh6cTOvLg==", + "dev": true, + "dependencies": { + "@es-joy/jsdoccomment": "~0.46.0", + "are-docs-informative": "^0.0.2", + "comment-parser": "1.4.1", + "debug": "^4.3.5", + "escape-string-regexp": "^4.0.0", + "esquery": "^1.6.0", + "parse-imports": "^2.1.1", + "semver": "^7.6.3", + "spdx-expression-parse": "^4.0.0", + "synckit": "^0.9.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-jsdoc/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-jsdoc/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.2.tgz", + "integrity": "sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==", "dev": true, "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -1999,18 +2164,42 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", + "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", "dev": true, "dependencies": { - "acorn": "^8.9.0", + "acorn": "^8.12.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "eslint-visitor-keys": "^4.0.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -2030,9 +2219,9 @@ } }, "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, "dependencies": { "estraverse": "^5.1.0" @@ -2207,15 +2396,15 @@ "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" }, "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, "dependencies": { - "flat-cache": "^3.0.4" + "flat-cache": "^4.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16.0.0" } }, "node_modules/fill-range": { @@ -2303,22 +2492,22 @@ } }, "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" + "flatted": "^3.2.9", + "keyv": "^4.5.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16" } }, "node_modules/flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "dev": true }, "node_modules/fn.name": { @@ -2545,15 +2734,12 @@ } }, "node_modules/globals": { - "version": "13.23.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", - "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", + "version": "15.8.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.8.0.tgz", + "integrity": "sha512-VZAJ4cewHTExBWDHR6yptdIBlx9YSSZuwojj9Nt5mBRXQzrKakDsVKQ1J63sklLvzAJm0X5+RpO4i3Y2hcOnFw==", "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -2565,12 +2751,6 @@ "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, "node_modules/has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -2732,9 +2912,9 @@ ] }, "node_modules/ignore": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", - "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", "dev": true, "engines": { "node": ">= 4" @@ -3067,6 +3247,15 @@ "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", "dev": true }, + "node_modules/jsdoc-type-pratt-parser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", + "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", + "dev": true, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -3079,6 +3268,12 @@ "node": ">=4" } }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", @@ -3175,6 +3370,15 @@ "node": ">=14.0.0" } }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, "node_modules/kuler": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", @@ -3969,6 +4173,19 @@ "node": ">=6" } }, + "node_modules/parse-imports": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/parse-imports/-/parse-imports-2.1.1.tgz", + "integrity": "sha512-TDT4HqzUiTMO1wJRwg/t/hYk8Wdp3iF/ToMIlAoVQfL1Xs/sTxq1dKWSMjMbQmIarfWKymOyly40+zmPHXMqCA==", + "dev": true, + "dependencies": { + "es-module-lexer": "^1.5.3", + "slashes": "^3.0.12" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", @@ -4654,6 +4871,12 @@ "url": "https://opencollective.com/sinon" } }, + "node_modules/slashes": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/slashes/-/slashes-3.0.12.tgz", + "integrity": "sha512-Q9VME8WyGkc7pJf6QEkj3wE+2CnvZMI+XJhwdTPR8Z/kWQRXi7boAWLDibRPyHRTUTPx5FaU7MsyrjI3yLB4HA==", + "dev": true + }, "node_modules/smart-buffer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", @@ -4718,6 +4941,28 @@ "node": ">=8" } }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", + "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.18", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.18.tgz", + "integrity": "sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==", + "dev": true + }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -4879,6 +5124,22 @@ "node": ">=8" } }, + "node_modules/synckit": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.1.tgz", + "integrity": "sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==", + "dev": true, + "dependencies": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, "node_modules/tar-fs": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.5.tgz", @@ -5008,18 +5269,6 @@ "node": ">=4" } }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", diff --git a/Framework/package.json b/Framework/package.json index b105d7e25..c8195761f 100644 --- a/Framework/package.json +++ b/Framework/package.json @@ -20,9 +20,9 @@ "test": "npm run eslint && npm run mocha", "coverage": "npm run eslint && nyc mocha Backend/test/** --exit", "mocha": "npm run mocha-frontend && npm run mocha-backend", - "mocha-frontend": "mocha --exit ./Frontend/test/mocha* --retries 2", - "mocha-backend": "mocha --exit ./Backend/test/*.js ./Backend/test/**/*.js --retries 2", - "eslint": "eslint --config ../.eslintrc.js Backend/ Frontend/ docs/tutorial/*.js", + "mocha-frontend": "mocha --exit ./Frontend/test/mocha* ", + "mocha-backend": "mocha --exit ./Backend/test/*.js ./Backend/test/**/*.js", + "eslint": "eslint --config eslint.config.js Backend/ Frontend/ docs/tutorial/*.js", "coverage-local": "nyc --reporter=lcov npm run mocha-backend" }, "nyc": { @@ -42,7 +42,11 @@ "ws": "^8.18.0" }, "devDependencies": { - "eslint": "^8.57.0", + "@eslint/js": "^9.7.0", + "@stylistic/eslint-plugin-js": "^2.3.0", + "eslint": "^9.7.0", + "eslint-plugin-jsdoc": "^48.7.0", + "globals": "^15.8.0", "mocha": "^10.7.0", "nock": "13.5.0", "nyc": "^17.0.0",