You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

269 rivejä
8.8 KiB

  1. const fs = require('fs-extra');
  2. const { clone } = require('../core/util');
  3. module.exports = {
  4. wait: function(options) {
  5. let delay = this.parseOptional(options.delay, 'number', 1000);
  6. return new Promise(resolve => setTimeout(resolve, delay))
  7. },
  8. log: function(options) {
  9. let message = this.parse(options.message);
  10. console.log(message);
  11. return message;
  12. },
  13. repeat: async function(options) {
  14. let repeater = this.parseRequired(options.repeat, '*', 'core.repeater: repeat is required.');
  15. let outputFilter = this.parseOptional(options.outputFilter, 'string', 'include'); // include/exclude
  16. let outputFields = this.parseOptional(options.outputFields, 'object'/*array[string]*/, []);
  17. let index = 0, data = [], parentData = this.data;
  18. switch (typeof repeater) {
  19. case 'boolean':
  20. repeater = repeater ? [0] : [];
  21. break;
  22. case 'string':
  23. repeater = repeater.split(',');
  24. break;
  25. case 'number':
  26. repeater = (n => {
  27. let a = [], i = 0;
  28. while (i < n) a.push(i++);
  29. return a;
  30. })(repeater);
  31. break;
  32. }
  33. if (!(Array.isArray(repeater) || repeater instanceof Object)) {
  34. throw new Error('Repeater data is not an array or object');
  35. }
  36. for (let key in repeater) {
  37. if (repeater.hasOwnProperty(key)) {
  38. let scope = {};
  39. this.data = {};
  40. if (repeater[key] instanceof Object) {
  41. for (var prop in repeater[key]) {
  42. if (repeater[key].hasOwnProperty(prop)) {
  43. scope[prop] = repeater[key][prop];
  44. if (outputFilter == 'exclude') {
  45. if (!outputFields.includes(prop)) {
  46. this.data[prop] = repeater[key][prop];
  47. }
  48. } else {
  49. if (outputFields.includes(prop)) {
  50. this.data[prop] = repeater[key][prop];
  51. }
  52. }
  53. }
  54. }
  55. }
  56. scope.$key = key;
  57. scope.$name = key;
  58. scope.$value = clone(repeater[key]);
  59. scope.$index = index;
  60. scope.$number = index + 1;
  61. scope.$oddeven = index % 2;
  62. if (repeater[key] == null) {
  63. repeater[key] = {};
  64. }
  65. this.scope = this.scope.create(scope, clone(repeater[key]));
  66. await this.exec(options.exec, true);
  67. this.scope = this.scope.parent;
  68. data.push({ ...this.data });
  69. index++;
  70. }
  71. }
  72. this.data = parentData;
  73. return data;
  74. },
  75. while: async function(options) {
  76. let max = this.parseOptional(options.max, 'number', Number.MAX_SAFE_INTEGER);
  77. let i = 0;
  78. while (this.parse(options.while)) {
  79. await this.exec(options.exec, true);
  80. if (++i == max) break;
  81. }
  82. },
  83. condition: async function(options) {
  84. let condition = this.parse(options.if);
  85. if (!!condition) {
  86. if (options.then) {
  87. await this.exec(options.then, true);
  88. }
  89. } else if (options.else) {
  90. await this.exec(options.else, true);
  91. }
  92. },
  93. conditions: async function(options) {
  94. if (Array.isArray(options.conditions)) {
  95. for (let condition of options.conditions) {
  96. let when = this.parse(condition.when);
  97. if (!!when) {
  98. return this.exec(condition.then, true);
  99. }
  100. }
  101. }
  102. },
  103. select: async function(options) {
  104. let expression = this.parse(options.expression);
  105. if (Array.isArray(options.cases)) {
  106. for (let item of options.cases) {
  107. let value = this.parse(item.value);
  108. if (expression === value) {
  109. return this.exec(item.exec, true);
  110. }
  111. }
  112. }
  113. },
  114. setvalue: function(options) {
  115. let key = this.parseOptional(options.key, 'string', '');
  116. let value = this.parse(options.value);
  117. if (key) this.set(key, value);
  118. return value;
  119. },
  120. setsession: function(options, name) {
  121. let value = this.parse(options.value);
  122. this.req.session[name] = value;
  123. return value;
  124. },
  125. removesession: function(options, name) {
  126. delete this.req.session[name];
  127. },
  128. setcookie: function(options, name) {
  129. options = this.parse(options);
  130. let cookieOptions = {
  131. domain: options.domain || undefined,
  132. httpOnly: !!options.httpOnly,
  133. maxAge: options.expires === 0 ? undefined : (options.expires || 30) * 24 * 60 * 60 * 1000, // from days to ms
  134. path: options.path || '/',
  135. secure: !!options.secure,
  136. sameSite: options.sameSite || false
  137. };
  138. this.setCookie(name, options.value, cookieOptions);
  139. },
  140. removecookie: function(options, name) {
  141. options = this.parse(options);
  142. let cookieOptions = {
  143. domain: options.domain || undefined,
  144. httpOnly: !!options.httpOnly,
  145. maxAge: options.expires === 0 ? undefined : (options.expires || 30) * 24 * 60 * 60 * 1000, // from days to ms
  146. path: options.path || '/',
  147. secure: !!options.secure,
  148. sameSite: !!options.sameSite
  149. };
  150. this.removeCookie(name, cookieOptions);
  151. },
  152. response: function(options) {
  153. let data = this.parseOptional(options.data, '*', null);
  154. let status = this.parseOptional(options.status, 'number', 200);
  155. let contentType = this.parseOptional(options.contentType, 'string', 'application/json');
  156. if (contentType != 'application/json') {
  157. this.res.set('Content-Type', contentType);
  158. this.res.status(status).send(data);
  159. } else {
  160. this.res.status(status).json(data);
  161. }
  162. },
  163. error: function(options) {
  164. let message = this.parseRequired(options.message, 'string', 'core.error: message is required.');
  165. throw new Error(message);
  166. },
  167. redirect: function(options) {
  168. let url = this.parseRequired(options.url, 'string', 'core.redirect: url is required.');
  169. let status = this.parseOptional(options.status, 'number', 302);
  170. this.res.redirect(status == 301 ? 301 : 302, url);
  171. },
  172. trycatch: async function(options) {
  173. try {
  174. await this.exec(options.try, true);
  175. } catch (error) {
  176. this.scope.set('$_ERROR', error.message || error);
  177. this.error = false;
  178. if (options.catch) {
  179. await this.exec(options.catch, true);
  180. }
  181. }
  182. },
  183. exec: async function(options) {
  184. var data = {};
  185. if (options.exec && fs.existsSync(`app/modules/lib/${options.exec}.json`)) {
  186. let parentData = this.data;
  187. this.data = {};
  188. this.scope = this.scope.create({ $_PARAM: this.parse(options.params) });
  189. await this.exec(await fs.readJSON(`app/modules/lib/${options.exec}.json`), true);
  190. data = this.data;
  191. this.scope = this.scope.parent;
  192. this.data = parentData;
  193. } else {
  194. throw new Error(`There is no action called '${options.exec}' found in the library.`);
  195. }
  196. return data;
  197. },
  198. group: async function(options, name) {
  199. if (name) {
  200. return this.sub(options.exec);
  201. } else {
  202. return this.exec(options.exec, true);
  203. }
  204. },
  205. parallel: async function(options, name) {
  206. let actions = options.exec.steps || options.exec;
  207. if (!Array.isArray(actions)) actions = [actions];
  208. return await Promise.all(actions.map(exec => {
  209. if (name) {
  210. return this.sub(exec);
  211. } else {
  212. return this.exec(exec, true);
  213. }
  214. }));
  215. },
  216. randomUUID: function(options) {
  217. const { randomUUID } = require('crypto');
  218. const { v4: uuidv4 } = require('uuid');
  219. return randomUUID ? randomUUID() : uuidv4();
  220. },
  221. };