const fs = require('fs-extra'); const { clone } = require('../core/util'); module.exports = { wait: function(options) { let delay = this.parseOptional(options.delay, 'number', 1000); return new Promise(resolve => setTimeout(resolve, delay)) }, log: function(options) { let message = this.parse(options.message); console.log(message); return message; }, repeat: async function(options) { let repeater = this.parseRequired(options.repeat, '*', 'core.repeater: repeat is required.'); let outputFilter = this.parseOptional(options.outputFilter, 'string', 'include'); // include/exclude let outputFields = this.parseOptional(options.outputFields, 'object'/*array[string]*/, []); let index = 0, data = [], parentData = this.data; switch (typeof repeater) { case 'boolean': repeater = repeater ? [0] : []; break; case 'string': repeater = repeater.split(','); break; case 'number': repeater = (n => { let a = [], i = 0; while (i < n) a.push(i++); return a; })(repeater); break; } if (!(Array.isArray(repeater) || repeater instanceof Object)) { throw new Error('Repeater data is not an array or object'); } for (let key in repeater) { if (Object.hasOwn(repeater, key)) { let scope = {}; this.data = {}; if (repeater[key] instanceof Object) { for (var prop in repeater[key]) { if (Object.hasOwn(repeater[key], prop)) { scope[prop] = repeater[key][prop]; if (outputFilter == 'exclude') { if (!outputFields.includes(prop)) { this.data[prop] = repeater[key][prop]; } } else { if (outputFields.includes(prop)) { this.data[prop] = repeater[key][prop]; } } } } } scope.$key = key; scope.$name = key; scope.$value = clone(repeater[key]); scope.$index = index; scope.$number = index + 1; scope.$oddeven = index % 2; if (repeater[key] == null) { repeater[key] = {}; } this.scope = this.scope.create(scope, clone(repeater[key])); await this.exec(options.exec, true); this.scope = this.scope.parent; data.push({ ...this.data }); index++; } } this.data = parentData; return data; }, while: async function(options) { let max = this.parseOptional(options.max, 'number', Number.MAX_SAFE_INTEGER); let i = 0; while (this.parse(options.while)) { await this.exec(options.exec, true); if (++i == max) break; } }, condition: async function(options) { let condition = this.parse(options.if); if (!!condition) { if (options.then) { await this.exec(options.then, true); } } else if (options.else) { await this.exec(options.else, true); } }, conditions: async function(options) { if (Array.isArray(options.conditions)) { for (let condition of options.conditions) { let when = this.parse(condition.when); if (!!when) { return this.exec(condition.then, true); } } } }, select: async function(options) { let expression = this.parse(options.expression); if (Array.isArray(options.cases)) { for (let item of options.cases) { let value = this.parse(item.value); if (expression === value) { return this.exec(item.exec, true); } } } }, setvalue: function(options) { let key = this.parseOptional(options.key, 'string', ''); let value = this.parse(options.value); if (key) this.set(key, value); return value; }, setsession: function(options, name) { let value = this.parse(options.value); this.req.session[name] = value; return value; }, removesession: function(options, name) { delete this.req.session[name]; }, setcookie: function(options, name) { options = this.parse(options); let cookieOptions = { domain: options.domain || undefined, httpOnly: !!options.httpOnly, maxAge: options.expires === 0 ? undefined : (options.expires || 30) * 24 * 60 * 60 * 1000, // from days to ms path: options.path || '/', secure: !!options.secure, sameSite: options.sameSite || false }; this.setCookie(name, options.value, cookieOptions); }, removecookie: function(options, name) { options = this.parse(options); let cookieOptions = { domain: options.domain || undefined, httpOnly: !!options.httpOnly, maxAge: options.expires === 0 ? undefined : (options.expires || 30) * 24 * 60 * 60 * 1000, // from days to ms path: options.path || '/', secure: !!options.secure, sameSite: !!options.sameSite }; this.removeCookie(name, cookieOptions); }, response: function(options) { let data = this.parseOptional(options.data, '*', null); let status = this.parseOptional(options.status, 'number', 200); let contentType = this.parseOptional(options.contentType, 'string', 'application/json'); if (contentType != 'application/json') { this.res.set('Content-Type', contentType); this.res.status(status).send(data); } else { this.res.status(status).json(data); } }, end: function(options) { this.res.json(this.data); }, error: function(options) { let message = this.parseRequired(options.message, 'string', 'core.error: message is required.'); throw new Error(message); }, redirect: function(options) { let url = this.parseRequired(options.url, 'string', 'core.redirect: url is required.'); let status = this.parseOptional(options.status, 'number', 302); this.res.redirect(status, url); }, trycatch: async function(options) { try { await this.exec(options.try, true); } catch (error) { this.scope.set('$_ERROR', error.message); this.error = false; if (options.catch) { await this.exec(options.catch, true); } } }, exec: async function(options) { var data = {}; if (options.exec && fs.existsSync(`app/modules/lib/${options.exec}.json`)) { let parentData = this.data; this.data = {}; this.scope = this.scope.create({ $_PARAM: this.parse(options.params) }); await this.exec(await fs.readJSON(`app/modules/lib/${options.exec}.json`), true); data = this.data; this.scope = this.scope.parent; this.data = parentData; } else { throw new Error(`There is no action called '${options.exec}' found in the library.`); } return data; }, group: async function(options, name) { if (name) { return this.sub(options.exec); } else { return this.exec(options.exec, true); } }, parallel: async function(options, name) { let actions = options.exec.steps || options.exec; if (!Array.isArray(actions)) actions = [actions]; return await Promise.all(actions.map(exec => { if (name) { return this.sub(exec); } else { return this.exec(exec, true); } })); }, randomUUID: function(options) { const { randomUUID } = require('crypto'); const { v4: uuidv4 } = require('uuid'); return randomUUID ? randomUUID() : uuidv4(); }, };