Main functions and classes of the FCF framework
Révision | ca2982a6e51461269aee4e506f1af8202727fed4 (tree) |
---|---|
l'heure | 2022-12-08 12:58:43 |
Auteur | vmarkin |
Commiter | vmarkin |
development
@@ -2,7 +2,7 @@ | ||
2 | 2 | const libPath = require("path"); |
3 | 3 | const libModule = require("module"); |
4 | 4 | |
5 | - let _gDirectories = { }; | |
5 | + let _directories = { }; | |
6 | 6 | |
7 | 7 | module.exports = new (class { |
8 | 8 |
@@ -21,19 +21,19 @@ | ||
21 | 21 | process.env.NODE_PATH = paths.join(":"); |
22 | 22 | } |
23 | 23 | libModule.Module._initPaths(); |
24 | - _gDirectories = {}; | |
24 | + _directories = {}; | |
25 | 25 | } |
26 | 26 | |
27 | 27 | resolveModule(a_module){ |
28 | 28 | a_module = a_module.split("\\")[0].split("/")[0]; |
29 | - if (!(a_module in _gDirectories)) { | |
29 | + if (!(a_module in _directories)) { | |
30 | 30 | try { |
31 | - _gDirectories[a_module] = libPath.dirname(require.resolve(`${a_module}/package.json`)); | |
31 | + _directories[a_module] = libPath.dirname(require.resolve(`${a_module}/package.json`)); | |
32 | 32 | } catch(e){ |
33 | 33 | return; |
34 | 34 | } |
35 | 35 | } |
36 | - return _gDirectories[a_module]; | |
36 | + return _directories[a_module]; | |
37 | 37 | } |
38 | 38 | |
39 | 39 | })(); |
@@ -1216,8 +1216,6 @@ | ||
1216 | 1216 | } |
1217 | 1217 | |
1218 | 1218 | |
1219 | - fcf.Exception = function () {}; | |
1220 | - | |
1221 | 1219 | fcf.styleToString = (a_name, a_value) => { |
1222 | 1220 | let result = ""; |
1223 | 1221 | if (typeof a_name == "object" && a_name !== null){ |
@@ -1333,7 +1331,6 @@ | ||
1333 | 1331 | /// - boolean noexcept = false - If the flag is true, then if the callback ends with an error, |
1334 | 1332 | /// the queue execution is not stopped and the handlers passed to catch are not called. |
1335 | 1333 | /// - mixed errorResult = undefined - The result returned by the result() method in case of an error |
1336 | - /// - boolean quiet = false - If true, then raw error messages are not printed to the console. | |
1337 | 1334 | /// @example |
1338 | 1335 | /// let actions = new fcf.Actions(async ()=>{ |
1339 | 1336 | /// ... |
@@ -1667,11 +1664,11 @@ | ||
1667 | 1664 | |
1668 | 1665 | /// @method fcf.Actions catch(function a_cb) |
1669 | 1666 | /// @brief Adds an error handler callback. |
1670 | - /// @details When the a_cb function is called, this is set to fcf.Actions object | |
1671 | - /// Exceptions thrown in the catch method handler are not handled and are thrown | |
1667 | + /// @details If the callback returns or throws an error object, | |
1668 | + /// then it replaces the current fcf.Actions error | |
1672 | 1669 | /// @param function a_cb - Error handler callback |
1673 | 1670 | /// - Has the following sigrature: |
1674 | - /// a_cb(Error a_error) | |
1671 | + /// undefined|Error a_cb(Error a_error) | |
1675 | 1672 | /// @result fcf.Actions - Self object |
1676 | 1673 | /// @example |
1677 | 1674 | /// (new fcf.Actions()) |
@@ -1686,10 +1683,19 @@ | ||
1686 | 1683 | catch(a_cb) { |
1687 | 1684 | if (!this._stack) |
1688 | 1685 | return; |
1689 | - if (a_cb && this._error) | |
1690 | - a_cb.call(this, this._error); | |
1691 | - else if (a_cb) | |
1686 | + this._flags |= ACTIONS_FLAGS_CATCH; | |
1687 | + if (a_cb && this._error) { | |
1688 | + try { | |
1689 | + let e = a_cb.call(this, this._error); | |
1690 | + if (e instanceof Error) { | |
1691 | + this._error = e; | |
1692 | + } | |
1693 | + } catch(e) { | |
1694 | + this._error = e; | |
1695 | + } | |
1696 | + } else if (a_cb) { | |
1692 | 1697 | this._errorcbs.push(a_cb); |
1698 | + } | |
1693 | 1699 | return this; |
1694 | 1700 | } |
1695 | 1701 |
@@ -1724,7 +1730,11 @@ | ||
1724 | 1730 | /// }); |
1725 | 1731 | finally(a_cb) { |
1726 | 1732 | if (a_cb && this._error) { |
1727 | - a_cb.call(this, undefined, {complete: ()=>{}, error: ()=>{}}); | |
1733 | + try { | |
1734 | + a_cb.call(this, undefined, {complete: ()=>{}, error: ()=>{}}); | |
1735 | + } catch (e){ | |
1736 | + this._error = e; | |
1737 | + } | |
1728 | 1738 | } else { |
1729 | 1739 | this._stack.push({cb: a_cb, args: undefined, finally: true, autoComplete: fcf.getParamCount(a_cb) < 2 }); |
1730 | 1740 | this._execute(); |
@@ -1758,10 +1768,14 @@ | ||
1758 | 1768 | if (!arguments.length) { |
1759 | 1769 | return this._error; |
1760 | 1770 | } |
1761 | - if (this._error) | |
1771 | + if (this._error){ | |
1772 | + if (a_error) { | |
1773 | + this._error = a_error; | |
1774 | + } | |
1762 | 1775 | return this; |
1776 | + } | |
1763 | 1777 | this._error = a_error ? a_error : new Error("Unknown error"); |
1764 | - this._callErrors(this._error); | |
1778 | + this._callErrors(); | |
1765 | 1779 | return this; |
1766 | 1780 | } |
1767 | 1781 |
@@ -1864,13 +1878,15 @@ | ||
1864 | 1878 | }) |
1865 | 1879 | } |
1866 | 1880 | |
1867 | - _callErrors(a_error) { | |
1868 | - let catchError; | |
1881 | + _callErrors() { | |
1869 | 1882 | for (let i = 0; i < this._errorcbs.length; ++i){ |
1870 | 1883 | try { |
1871 | - this._errorcbs[i].call(this, a_error); | |
1884 | + let e = this._errorcbs[i].call(this, this._error); | |
1885 | + if (e instanceof Error) { | |
1886 | + this._error = e; | |
1887 | + } | |
1872 | 1888 | } catch(e) { |
1873 | - fcf.log.err("FCF", "An exception was caught in the catch block of the Actions object while handling an error. Error: ", e); | |
1889 | + this._error = e; | |
1874 | 1890 | } |
1875 | 1891 | } |
1876 | 1892 | for (let i = 0; i < this._stack.length; ++i){ |
@@ -1878,14 +1894,17 @@ | ||
1878 | 1894 | try { |
1879 | 1895 | this._stack[i].cb.call(this, undefined, {complete: ()=>{}, error: ()=>{}}); |
1880 | 1896 | } catch(e) { |
1881 | - fcf.log.err("FCF", "An exception was caught in the finally block of the Actions object while handling an error. Error: ", e); | |
1897 | + this._error = e; | |
1882 | 1898 | } |
1883 | 1899 | } |
1884 | 1900 | } |
1885 | - | |
1886 | 1901 | if (!(this._flags & ACTIONS_FLAGS_QUIET)) { |
1887 | - if (!this._errorcbs.length){ | |
1888 | - fcf.log.err("FCF", "Unhandled error in fcf.Actions (to handle catch method or \"quiet\" flag). Error: ", a_error) | |
1902 | + if (!(this._flags & ACTIONS_FLAGS_CATCH)){ | |
1903 | + setTimeout(()=>{ | |
1904 | + if (!(this._flags & ACTIONS_FLAGS_CATCH)){ | |
1905 | + fcf.log.err("FCF", "Unhandled error in fcf.Actions (to handle catch method or \"quiet\" flag).", this._error) | |
1906 | + } | |
1907 | + }, 0); | |
1889 | 1908 | } |
1890 | 1909 | } |
1891 | 1910 | } |
@@ -1939,7 +1958,7 @@ | ||
1939 | 1958 | self._flags &= ~ACTIONS_FLAGS_RUN; |
1940 | 1959 | self._result = undefined; |
1941 | 1960 | self._error = a_error ? a_error : new Error("Unknown error"); |
1942 | - self._callErrors(self._error); | |
1961 | + self._callErrors(); | |
1943 | 1962 | }, |
1944 | 1963 | }; |
1945 | 1964 | let args = []; |
@@ -1999,6 +2018,7 @@ | ||
1999 | 2018 | const ACTIONS_FLAGS_NOEXCEPT = 2; |
2000 | 2019 | const ACTIONS_FLAGS_RUN = 4; |
2001 | 2020 | const ACTIONS_FLAGS_QUIET = 8; |
2021 | + const ACTIONS_FLAGS_CATCH = 16; | |
2002 | 2022 | |
2003 | 2023 | |
2004 | 2024 |
@@ -2050,7 +2070,7 @@ | ||
2050 | 2070 | /// <head> |
2051 | 2071 | /// <script src="/node_modules/fcf-framework-core/fcf.js"></script> |
2052 | 2072 | /// <script> |
2053 | - /// // Adding data about the new package "package" to the configuration | |
2073 | + /// // Adding data about the new "package" package to the configuration | |
2054 | 2074 | /// fcf.configuration.append({ |
2055 | 2075 | /// webModules: { |
2056 | 2076 | /// |
@@ -3484,8 +3504,9 @@ | ||
3484 | 3504 | fcf.NDetails.messages[a_messageName] = a_messageText; |
3485 | 3505 | } |
3486 | 3506 | |
3487 | - fcf.Exception = class { | |
3507 | + fcf.Exception = class Exception extends Error{ | |
3488 | 3508 | constructor(a_nameOrMessageOrException, a_args, a_subException) { |
3509 | + super(a_nameOrMessageOrException); | |
3489 | 3510 | let exceptionName; |
3490 | 3511 | let template; |
3491 | 3512 | let stackTxt; |
@@ -4248,12 +4269,11 @@ | ||
4248 | 4269 | |
4249 | 4270 | for(var i = 2; i < arguments.length; ++i) { |
4250 | 4271 | if (_isServer && typeof arguments[i] == "object"){ |
4251 | - if (arguments[i] instanceof Error) { | |
4252 | - outputArr.push(arguments[i].toString()); | |
4253 | - outputArr.push(arguments[i].stack); | |
4254 | - } else if (arguments[i] instanceof fcf.Exception){ | |
4272 | + if (arguments[i] instanceof fcf.Exception){ | |
4255 | 4273 | outputArr.push(arguments[i].toString(true, true)); |
4256 | 4274 | outputArr.push("\nStack:\n" + fcf.Exception.stackToString(arguments[i].stackArr)); |
4275 | + } else if (arguments[i] instanceof Error) { | |
4276 | + outputArr.push(arguments[i].stack); | |
4257 | 4277 | } else { |
4258 | 4278 | outputArr.push(JSON.stringify(arguments[i], 0, 2)); |
4259 | 4279 | } |
@@ -4438,6 +4458,131 @@ | ||
4438 | 4458 | } |
4439 | 4459 | |
4440 | 4460 | |
4461 | + | |
4462 | + fcf.parseUrl = (a_url)=> { | |
4463 | + var result = {}; | |
4464 | + var sep = a_url.indexOf('?'); | |
4465 | + | |
4466 | + anchorArr = a_url.split("#"); | |
4467 | + a_url = anchorArr[0]; | |
4468 | + result.anchor = anchorArr[1]; | |
4469 | + | |
4470 | + if (sep === -1) { | |
4471 | + result.url = a_url; | |
4472 | + result.referer = a_url; | |
4473 | + result.urlArgs = {}; | |
4474 | + } else { | |
4475 | + var rawQuery = a_url.substr(sep+1); | |
4476 | + result.referer = a_url.substr(0, sep); | |
4477 | + result.url = a_url; | |
4478 | + result.urlArgs = {}; | |
4479 | + var arr = fcf.str(rawQuery).split('&'); | |
4480 | + for(var i = 0; i < arr.length; ++i) { | |
4481 | + var val = arr[i].split('='); | |
4482 | + result.urlArgs[decodeURIComponent(fcf.str(val[0]))] = decodeURIComponent(fcf.str(val[1])); | |
4483 | + } | |
4484 | + } | |
4485 | + | |
4486 | + if (result.referer[0] == '/') { | |
4487 | + result.uri = result.referer.substr(1); | |
4488 | + result.server = ''; | |
4489 | + result.protocol = ''; | |
4490 | + } else { | |
4491 | + var pos = result.referer.indexOf('://'); | |
4492 | + if (pos !== -1) { | |
4493 | + var pos2 = result.referer.indexOf('/', pos+3); | |
4494 | + if (pos2 === -1) { | |
4495 | + result.uri = '/'; | |
4496 | + result.server = result.referer.substr(pos+3); | |
4497 | + result.protocol = result.referer.substr(0, pos); | |
4498 | + } else { | |
4499 | + result.uri = result.referer.substr(pos2); | |
4500 | + result.server = result.referer.substr(pos+3, pos2 - (pos+3)); | |
4501 | + result.protocol = result.referer.substr(0, pos); | |
4502 | + } | |
4503 | + } else { | |
4504 | + result.server = ''; | |
4505 | + result.protocol = ''; | |
4506 | + result.uri = result.referer; | |
4507 | + } | |
4508 | + } | |
4509 | + | |
4510 | + result.args = fcf.append({}, result.urlArgs); | |
4511 | + | |
4512 | + let serverArr = result.server.split(":"); | |
4513 | + result.server = serverArr[0]; | |
4514 | + result.port = serverArr[1]; | |
4515 | + | |
4516 | + return result; | |
4517 | + } | |
4518 | + | |
4519 | + fcf.buildUrl = (a_url, a_args, a_anchor) => { | |
4520 | + var urlInfo = typeof a_url == "object" ? a_url : fcf.parseUrl(a_url); | |
4521 | + a_url = urlInfo.referer; | |
4522 | + a_args = fcf.append({}, urlInfo.urlArgs, a_args); | |
4523 | + | |
4524 | + var first = true; | |
4525 | + for(var k in a_args) { | |
4526 | + if (first) | |
4527 | + a_url += a_url.indexOf('?') != -1 ? '&' : '?'; | |
4528 | + else | |
4529 | + a_url += '&'; | |
4530 | + | |
4531 | + a_url += k; | |
4532 | + if (a_args[k] !== null && a_args[k] !== undefined) { | |
4533 | + a_url += '='; | |
4534 | + if (typeof a_args[k] != 'object') { | |
4535 | + a_url += encodeURIComponent(fcf.str(a_args[k])); | |
4536 | + } else { | |
4537 | + a_url += encodeURIComponent(JSON.stringify(a_args[k])); | |
4538 | + } | |
4539 | + } | |
4540 | + | |
4541 | + first = false; | |
4542 | + } | |
4543 | + | |
4544 | + if (!fcf.empty(a_anchor)) | |
4545 | + a_url += "#" + a_anchor; | |
4546 | + else if (!fcf.empty(urlInfo.anchor)) | |
4547 | + a_url += "#" + urlInfo.anchor; | |
4548 | + | |
4549 | + return a_url; | |
4550 | + } | |
4551 | + | |
4552 | + fcf.addException("LOAD_MODULE", "Failed to load JS module @{{module}}@"); | |
4553 | + fcf.addException("LOAD_UNITEST_MODULE", "Failed to load fcf-framework-unitest module. Install the missing module to perform testing: $ npm install fcf-framework-unitest"); | |
4554 | + | |
4555 | + fcf.test = function(a_part, a_group, a_name, a_cbtest){ | |
4556 | + if (!_isServer) { | |
4557 | + let route = fcf.parseUrl(window.location.href); | |
4558 | + if (!route.args.fcf_unitest_port || !route.args.fcf_unitest_host){ | |
4559 | + return; | |
4560 | + } | |
4561 | + } | |
4562 | + let currentArguments = arguments; | |
4563 | + let loadModule = false; | |
4564 | + return fcf.actions() | |
4565 | + .then(()=>{ | |
4566 | + return fcf.require("fcf-framework-unitest", {showError: false}); | |
4567 | + }) | |
4568 | + .catch((a_error)=>{ | |
4569 | + if (!loadModule) { | |
4570 | + return new fcf.Exception("LOAD_UNITEST_MODULE", a_error); | |
4571 | + } | |
4572 | + }) | |
4573 | + .then(([unitest]) => { | |
4574 | + if (!unitest) { | |
4575 | + throw new fcf.Exception("LOAD_MODULE", {module: "fcf-framework-unitest"}); | |
4576 | + } | |
4577 | + loadModule = true; | |
4578 | + unitest.add.apply(unitest, currentArguments); | |
4579 | + }) | |
4580 | + .catch((a_error)=>{ | |
4581 | + fcf.log.err("unitest", a_error); | |
4582 | + }); | |
4583 | + } | |
4584 | + | |
4585 | + | |
4441 | 4586 | fcf.Configuration = class { |
4442 | 4587 | constructor(a_options) { |
4443 | 4588 | this.moduleDirectories = []; |