diff --git a/package-lock.json b/package-lock.json index 5a07302c42..2c61990047 100644 --- a/package-lock.json +++ b/package-lock.json @@ -361,18 +361,18 @@ } }, "@eslint/eslintrc": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", - "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.0.4.tgz", + "integrity": "sha512-h8Vx6MdxwWI2WM8/zREHMoqdgLNXEL4QX3MWSVMdyNJGvXVOs+6lp+m2hc3FnuMHDc4poxFNI20vCk0OmI4G0Q==", "dev": true, "requires": { "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", + "debug": "^4.3.2", + "espree": "^9.0.0", "globals": "^13.9.0", "ignore": "^4.0.6", "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", + "js-yaml": "^4.1.0", "minimatch": "^3.0.4", "strip-json-comments": "^3.1.1" }, @@ -389,32 +389,31 @@ "uri-js": "^4.2.2" } }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "requires": { - "sprintf-js": "~1.0.2" + "ms": "2.1.2" } }, "globals": { - "version": "13.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", - "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", + "version": "13.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz", + "integrity": "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==", "dev": true, "requires": { "type-fest": "^0.20.2" } }, "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "^2.0.1" } }, "json-schema-traverse": { @@ -422,6 +421,12 @@ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true } } }, @@ -431,6 +436,23 @@ "integrity": "sha512-82cpyJyKRoQoRi+14ibCeGPu0CwypgtBAdBhq1WfvagpCZNKqwXbKwXllYSMG91DhmG4jt9gN8eP6lGOtozuaw==", "dev": true }, + "@humanwhocodes/config-array": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.6.0.tgz", + "integrity": "sha512-JQlEKbcgEUjBFhLIF4iqM7u/9lwgHRBcpHrmUNCALK0Q3amXN6lxdoXLnF0sm11E9VqTmBALR87IlUg1bZ8A9A==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + } + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, "@hutson/parse-repository-url": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz", @@ -2832,9 +2854,9 @@ "dev": true }, "acorn": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.1.2.tgz", - "integrity": "sha512-o96FZLJBPY1lvTuJylGA9Bk3t/GKPPJG8H0ydQQl01crzwJgspa4AEIq/pVTXigmK0PHVQhiAtn8WMBLL9D2WA==" + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", + "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==" }, "acorn-dynamic-import": { "version": "4.0.0", @@ -2847,6 +2869,11 @@ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==" + }, "add-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/add-stream/-/add-stream-1.0.0.tgz", @@ -3104,12 +3131,6 @@ "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" }, - "astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true - }, "async-each": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", @@ -5335,46 +5356,47 @@ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "eslint": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.24.0.tgz", - "integrity": "sha512-k9gaHeHiFmGCDQ2rEfvULlSLruz6tgfA8DEn+rY9/oYPFFTlz55mM/Q/Rij1b2Y42jwZiK3lXvNTw6w6TXzcKQ==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.2.0.tgz", + "integrity": "sha512-erw7XmM+CLxTOickrimJ1SiF55jiNlVSp2qqm0NuBWPtHYQCegD5ZMaW0c3i5ytPqL+SSLaCxdvQXFPLJn+ABw==", "dev": true, "requires": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.0", + "@eslint/eslintrc": "^1.0.4", + "@humanwhocodes/config-array": "^0.6.0", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", - "debug": "^4.0.1", + "debug": "^4.3.2", "doctrine": "^3.0.0", "enquirer": "^2.3.5", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^6.0.0", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.0.0", + "espree": "^9.0.0", "esquery": "^1.4.0", "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.0.0", + "glob-parent": "^6.0.1", "globals": "^13.6.0", "ignore": "^4.0.6", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", + "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", - "lodash": "^4.17.21", + "lodash.merge": "^4.6.2", "minimatch": "^3.0.4", "natural-compare": "^1.4.0", "optionator": "^0.9.1", "progress": "^2.0.0", - "regexpp": "^3.1.0", + "regexpp": "^3.2.0", "semver": "^7.2.1", - "strip-ansi": "^6.0.0", + "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", - "table": "^6.0.4", "text-table": "^0.2.0", "v8-compile-cache": "^2.0.3" }, @@ -5406,15 +5428,6 @@ "color-convert": "^2.0.1" } }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -5451,20 +5464,50 @@ "which": "^2.0.1" } }, + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-6.0.0.tgz", + "integrity": "sha512-uRDL9MWmQCkaFus8RF5K9/L/2fn+80yoW3jkD53l4shjCh26fCtvJGasxjUqP5OT87SYTxCVA3BwTUzuELx9kA==", "dev": true, "requires": { "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" } }, "globals": { - "version": "13.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", - "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", + "version": "13.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz", + "integrity": "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -5477,13 +5520,12 @@ "dev": true }, "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "^2.0.1" } }, "json-schema-traverse": { @@ -5492,6 +5534,12 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, "path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -5543,49 +5591,43 @@ } }, "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", "dev": true, "requires": { - "eslint-visitor-keys": "^1.1.0" + "eslint-visitor-keys": "^2.0.0" }, "dependencies": { "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true } } }, "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz", + "integrity": "sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA==", "dev": true }, "espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.0.0.tgz", + "integrity": "sha512-r5EQJcYZ2oaGbeR0jR0fFVijGOcwai07/690YRXLINuhmVeRY4UKSAsQPe/0BNuDgwP7Ophoc1PRsr2E3tkbdQ==", "dev": true, "requires": { - "acorn": "^7.4.0", + "acorn": "^8.5.0", "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" + "eslint-visitor-keys": "^3.0.0" }, "dependencies": { "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true - }, - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", + "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==", "dev": true } } @@ -5606,9 +5648,9 @@ }, "dependencies": { "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true } } @@ -5980,9 +6022,9 @@ } }, "flatted": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz", - "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.4.tgz", + "integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==", "dev": true }, "flush-write-stream": { @@ -8084,12 +8126,6 @@ "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", "dev": true }, - "lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", - "dev": true - }, "lodash.flattendeep": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", @@ -8107,6 +8143,12 @@ "integrity": "sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc=", "dev": true }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, "lodash.template": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", @@ -8126,12 +8168,6 @@ "lodash._reinterpolate": "^3.0.0" } }, - "lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", - "dev": true - }, "log-driver": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz", @@ -11550,49 +11586,6 @@ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" }, - "slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - } - } - }, "slide": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", @@ -12116,54 +12109,6 @@ "integrity": "sha1-O5hzuKkB5Hxu/iFSajrDcu8ou8c=", "dev": true }, - "table": { - "version": "6.7.2", - "resolved": "https://registry.npmjs.org/table/-/table-6.7.2.tgz", - "integrity": "sha512-UFZK67uvyNivLeQbVtkiUs8Uuuxv24aSL4/Vil2PJVtMgU8Lx0CYkP12uCGa3kjyQzOSgV1+z9Wkb82fCGsO0g==", - "dev": true, - "requires": { - "ajv": "^8.0.1", - "lodash.clonedeep": "^4.5.0", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - } - } - }, "taffydb": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz", diff --git a/package.json b/package.json index 3952133d3c..7783ee9d05 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "colors": "1.4.0", "coveralls": "3.1.0", "dayjs": "1.10.4", - "eslint": "7.24.0", + "eslint": "8.2.0", "jsdoc": "^3.6.7", "glob": "^7.1.7", "lerna": "^4.0.0", diff --git a/packages/concerto-cli/package.json b/packages/concerto-cli/package.json index fa45b675f6..6d0676c7a6 100644 --- a/packages/concerto-cli/package.json +++ b/packages/concerto-cli/package.json @@ -31,7 +31,7 @@ "chai": "4.3.4", "chai-as-promised": "7.1.1", "chai-things": "0.2.0", - "eslint": "7.24.0", + "eslint": "8.2.0", "jsdoc": "^3.6.7", "license-check-and-add": "2.3.6", "mocha": "8.3.2", diff --git a/packages/concerto-core/.eslintrc.yml b/packages/concerto-core/.eslintrc.yml index 497520656f..cff713bc96 100644 --- a/packages/concerto-core/.eslintrc.yml +++ b/packages/concerto-core/.eslintrc.yml @@ -4,7 +4,7 @@ env: mocha: true extends: 'eslint:recommended' parserOptions: - ecmaVersion: 12 + ecmaVersion: 13 sourceType: script rules: indent: diff --git a/packages/concerto-core/api.txt b/packages/concerto-core/api.txt index 53a3d6c1cc..5cd60f630e 100644 --- a/packages/concerto-core/api.txt +++ b/packages/concerto-core/api.txt @@ -110,33 +110,35 @@ class ModelFileDownloader { + Promise downloadExternalDependencies(ModelFile[],Object) + Promise runJob(Object,Object) } +class MetaModel { + void createMetaModelManager() - + object validateMetaModel() - + object createNameTable() - + string resolveName() - + object resolveTypeNames() - + object resolveMetaModel() - + object enumPropertyToMetaModel() - + object decoratorArgToMetaModel() - + object decoratorToMetaModel() - + object decoratorsToMetaModel() - + object propertyToMetaModel() - + object relationshipToMetaModel() - + object enumDeclToMetaModel() - + object conceptDeclToMetaModel() - + object declToMetaModel() - + object modelToMetaModel() - + object modelFileToMetaModel() - + object modelManagerToMetaModel() - + string decoratorArgFromMetaModel() - + string decoratorFromMetaModel() - + string decoratorsFromMetaModel() - + string propertyFromMetaModel() - + string declFromMetaModel() - + string ctoFromMetaModel() - + object modelManagerFromMetaModel() - + object ctoToMetaModel() - + object ctoToMetaModelAndResolve() + + object validateMetaModel(object) + + object createNameTable(object) + + string resolveName(string,object) + + object resolveTypeNames(object,object) + + object resolveMetaModel(object,object) + + object enumPropertyToMetaModel(object) + + object decoratorArgToMetaModel(object) + + object decoratorToMetaModel(object) + + object decoratorsToMetaModel(object) + + object propertyToMetaModel(object) + + object relationshipToMetaModel(object) + + object enumDeclToMetaModel(object) + + object conceptDeclToMetaModel(object) + + object declToMetaModel(object) + + object modelToMetaModel(object,boolean) + + object modelFileToMetaModel(object,boolean) + + object modelManagerToMetaModel(object,boolean,boolean) + + string decoratorArgFromMetaModel(object) + + string decoratorFromMetaModel(object) + + string decoratorsFromMetaModel(object,string) + + string propertyFromMetaModel(object) + + string declFromMetaModel(object) + + string ctoFromMetaModel(object,boolean) + + object modelManagerFromMetaModel(object,boolean) + + object ctoToMetaModel(string,boolean) + + object ctoToMetaModelAndResolve(string,boolean) +} class ModelFile { + void constructor(ModelManager,string,string) throws IllegalModelException + Boolean isSystemModelFile() diff --git a/packages/concerto-core/changelog.txt b/packages/concerto-core/changelog.txt index 58c42fcbb4..f14de6c6de 100644 --- a/packages/concerto-core/changelog.txt +++ b/packages/concerto-core/changelog.txt @@ -24,6 +24,10 @@ # Note that the latest public API is documented using JSDocs and is available in api.txt. # +Version 1.2.2 {8149560555027394c95a893c1e442d67} 2021-11-15 +- Convert MetaModel to a class for Typescript + Webpack compatability +- Update Acorn to latest and refactor the JavaScript parser so we can use static class members + Version 1.2.2 {b19318bb094e5da7bdff192cf9a3b4f2} 2021-08-12 - Fixes to metamodel, including terminology changes - Ability to roundtrip model manager to metamodel diff --git a/packages/concerto-core/lib/introspect/metamodel.js b/packages/concerto-core/lib/introspect/metamodel.js index cb80bc0034..e2d251ceb5 100644 --- a/packages/concerto-core/lib/introspect/metamodel.js +++ b/packages/concerto-core/lib/introspect/metamodel.js @@ -19,1069 +19,1069 @@ const ModelManager = require('../modelmanager'); const Factory = require('../factory'); const Serializer = require('../serializer'); -const metaModelCto = `/* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -namespace concerto.metamodel - /** - * The metadmodel for Concerto files + * Class to work with the Concerto metamodel */ -concept TypeIdentifier { - o String name - o String namespace optional -} - -abstract concept DecoratorLiteral { -} - -concept DecoratorString extends DecoratorLiteral { - o String value -} - -concept DecoratorNumber extends DecoratorLiteral { - o Double value -} - -concept DecoratorBoolean extends DecoratorLiteral { - o Boolean value -} - -concept DecoratorTypeReference extends DecoratorLiteral { - o TypeIdentifier type - o Boolean isArray default=false -} - -concept Decorator { - o String name - o DecoratorLiteral[] arguments optional -} - -concept Identified { -} - -concept IdentifiedBy extends Identified { - o String name -} - -abstract concept Declaration {} - -concept EnumDeclaration extends Declaration { - o String name regex=/^(?!null|true|false)(\\p{Lu}|\\p{Ll}|\\p{Lt}|\\p{Lm}|\\p{Lo}|\\p{Nl}|\\$|_|\\\\u[0-9A-Fa-f]{4})(?:\\p{Lu}|\\p{Ll}|\\p{Lt}|\\p{Lm}|\\p{Lo}|\\p{Nl}|\\$|_|\\\\u[0-9A-Fa-f]{4}|\\p{Mn}|\\p{Mc}|\\p{Nd}|\\p{Pc}|\\u200C|\\u200D)*$/u - o EnumProperty[] properties -} - -concept EnumProperty { - o String name regex=/^(?!null|true|false)(\\p{Lu}|\\p{Ll}|\\p{Lt}|\\p{Lm}|\\p{Lo}|\\p{Nl}|\\$|_|\\\\u[0-9A-Fa-f]{4})(?:\\p{Lu}|\\p{Ll}|\\p{Lt}|\\p{Lm}|\\p{Lo}|\\p{Nl}|\\$|_|\\\\u[0-9A-Fa-f]{4}|\\p{Mn}|\\p{Mc}|\\p{Nd}|\\p{Pc}|\\u200C|\\u200D)*$/u - o Decorator[] decorators optional -} - -concept ConceptDeclaration extends Declaration { - o String name regex=/^(?!null|true|false)(\\p{Lu}|\\p{Ll}|\\p{Lt}|\\p{Lm}|\\p{Lo}|\\p{Nl}|\\$|_|\\\\u[0-9A-Fa-f]{4})(?:\\p{Lu}|\\p{Ll}|\\p{Lt}|\\p{Lm}|\\p{Lo}|\\p{Nl}|\\$|_|\\\\u[0-9A-Fa-f]{4}|\\p{Mn}|\\p{Mc}|\\p{Nd}|\\p{Pc}|\\u200C|\\u200D)*$/u - o Decorator[] decorators optional - o Boolean isAbstract default=false - o Identified identified optional - o TypeIdentifier superType optional - o Property[] properties -} - -concept AssetDeclaration extends ConceptDeclaration { -} - -concept ParticipantDeclaration extends ConceptDeclaration { -} - -concept TransactionDeclaration extends ConceptDeclaration { -} - -concept EventDeclaration extends ConceptDeclaration { -} - -abstract concept Property { - o String name regex=/^(?!null|true|false)(\\p{Lu}|\\p{Ll}|\\p{Lt}|\\p{Lm}|\\p{Lo}|\\p{Nl}|\\$|_|\\\\u[0-9A-Fa-f]{4})(?:\\p{Lu}|\\p{Ll}|\\p{Lt}|\\p{Lm}|\\p{Lo}|\\p{Nl}|\\$|_|\\\\u[0-9A-Fa-f]{4}|\\p{Mn}|\\p{Mc}|\\p{Nd}|\\p{Pc}|\\u200C|\\u200D)*$/u - o Boolean isArray default=false - o Boolean isOptional default=false - o Decorator[] decorators optional -} - -concept RelationshipProperty extends Property { - o TypeIdentifier type -} - -concept ObjectProperty extends Property { - o String defaultValue optional - o TypeIdentifier type -} - -concept BooleanProperty extends Property { - o Boolean defaultValue optional -} - -concept DateTimeProperty extends Property { -} - -concept StringProperty extends Property { - o String defaultValue optional - o StringRegexValidator validator optional -} - -concept StringRegexValidator { - o String regex -} - -concept DoubleProperty extends Property { - o Double defaultValue optional - o DoubleDomainValidator validator optional -} - -concept DoubleDomainValidator { - o Double lower optional - o Double upper optional -} - -concept IntegerProperty extends Property { - o Integer defaultValue optional - o IntegerDomainValidator validator optional -} - -concept IntegerDomainValidator { - o Integer lower optional - o Integer upper optional -} - -concept LongProperty extends Property { - o Long defaultValue optional - o LongDomainValidator validator optional -} - -concept LongDomainValidator { - o Long lower optional - o Long upper optional -} - -abstract concept Import { - o String namespace - o String uri optional -} - -concept ImportAll extends Import { -} - -concept ImportType extends Import { - o String name -} - -concept Model { - o String namespace - o Import[] imports optional - o Declaration[] declarations optional -} - -concept Models { - o Model[] models -} -`; +class MetaModel { + + /** + * The metamodel itself, as a CTO string + */ + static metaModelCto = `/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + namespace concerto.metamodel + + /** + * The metadmodel for Concerto files + */ + concept TypeIdentifier { + o String name + o String namespace optional + } + + abstract concept DecoratorLiteral { + } + + concept DecoratorString extends DecoratorLiteral { + o String value + } + + concept DecoratorNumber extends DecoratorLiteral { + o Double value + } + + concept DecoratorBoolean extends DecoratorLiteral { + o Boolean value + } + + concept DecoratorTypeReference extends DecoratorLiteral { + o TypeIdentifier type + o Boolean isArray default=false + } + + concept Decorator { + o String name + o DecoratorLiteral[] arguments optional + } + + concept Identified { + } + + concept IdentifiedBy extends Identified { + o String name + } + + abstract concept Declaration {} + + concept EnumDeclaration extends Declaration { + o String name regex=/^(?!null|true|false)(\\p{Lu}|\\p{Ll}|\\p{Lt}|\\p{Lm}|\\p{Lo}|\\p{Nl}|\\$|_|\\\\u[0-9A-Fa-f]{4})(?:\\p{Lu}|\\p{Ll}|\\p{Lt}|\\p{Lm}|\\p{Lo}|\\p{Nl}|\\$|_|\\\\u[0-9A-Fa-f]{4}|\\p{Mn}|\\p{Mc}|\\p{Nd}|\\p{Pc}|\\u200C|\\u200D)*$/u + o EnumProperty[] properties + } + + concept EnumProperty { + o String name regex=/^(?!null|true|false)(\\p{Lu}|\\p{Ll}|\\p{Lt}|\\p{Lm}|\\p{Lo}|\\p{Nl}|\\$|_|\\\\u[0-9A-Fa-f]{4})(?:\\p{Lu}|\\p{Ll}|\\p{Lt}|\\p{Lm}|\\p{Lo}|\\p{Nl}|\\$|_|\\\\u[0-9A-Fa-f]{4}|\\p{Mn}|\\p{Mc}|\\p{Nd}|\\p{Pc}|\\u200C|\\u200D)*$/u + o Decorator[] decorators optional + } + + concept ConceptDeclaration extends Declaration { + o String name regex=/^(?!null|true|false)(\\p{Lu}|\\p{Ll}|\\p{Lt}|\\p{Lm}|\\p{Lo}|\\p{Nl}|\\$|_|\\\\u[0-9A-Fa-f]{4})(?:\\p{Lu}|\\p{Ll}|\\p{Lt}|\\p{Lm}|\\p{Lo}|\\p{Nl}|\\$|_|\\\\u[0-9A-Fa-f]{4}|\\p{Mn}|\\p{Mc}|\\p{Nd}|\\p{Pc}|\\u200C|\\u200D)*$/u + o Decorator[] decorators optional + o Boolean isAbstract default=false + o Identified identified optional + o TypeIdentifier superType optional + o Property[] properties + } + + concept AssetDeclaration extends ConceptDeclaration { + } + + concept ParticipantDeclaration extends ConceptDeclaration { + } + + concept TransactionDeclaration extends ConceptDeclaration { + } + + concept EventDeclaration extends ConceptDeclaration { + } + + abstract concept Property { + o String name regex=/^(?!null|true|false)(\\p{Lu}|\\p{Ll}|\\p{Lt}|\\p{Lm}|\\p{Lo}|\\p{Nl}|\\$|_|\\\\u[0-9A-Fa-f]{4})(?:\\p{Lu}|\\p{Ll}|\\p{Lt}|\\p{Lm}|\\p{Lo}|\\p{Nl}|\\$|_|\\\\u[0-9A-Fa-f]{4}|\\p{Mn}|\\p{Mc}|\\p{Nd}|\\p{Pc}|\\u200C|\\u200D)*$/u + o Boolean isArray default=false + o Boolean isOptional default=false + o Decorator[] decorators optional + } + + concept RelationshipProperty extends Property { + o TypeIdentifier type + } + + concept ObjectProperty extends Property { + o String defaultValue optional + o TypeIdentifier type + } + + concept BooleanProperty extends Property { + o Boolean defaultValue optional + } + + concept DateTimeProperty extends Property { + } + + concept StringProperty extends Property { + o String defaultValue optional + o StringRegexValidator validator optional + } + + concept StringRegexValidator { + o String regex + } + + concept DoubleProperty extends Property { + o Double defaultValue optional + o DoubleDomainValidator validator optional + } + + concept DoubleDomainValidator { + o Double lower optional + o Double upper optional + } + + concept IntegerProperty extends Property { + o Integer defaultValue optional + o IntegerDomainValidator validator optional + } + + concept IntegerDomainValidator { + o Integer lower optional + o Integer upper optional + } + + concept LongProperty extends Property { + o Long defaultValue optional + o LongDomainValidator validator optional + } + + concept LongDomainValidator { + o Long lower optional + o Long upper optional + } + + abstract concept Import { + o String namespace + o String uri optional + } + + concept ImportAll extends Import { + } + + concept ImportType extends Import { + o String name + } + + concept Model { + o String namespace + o Import[] imports optional + o Declaration[] declarations optional + } + + concept Models { + o Model[] models + } + `; + + /** + * Create a metamodel manager (for validation against the metamodel) + * @return {*} the metamodel manager + */ + static createMetaModelManager() { + const metaModelManager = new ModelManager(); + metaModelManager.addModelFile(MetaModel.metaModelCto, 'concerto.metamodel'); + return metaModelManager; + } -/** - * Create a metamodel manager (for validation against the metamodel) - * @return {*} the metamodel manager - */ -function createMetaModelManager() { - const metaModelManager = new ModelManager(); - metaModelManager.addModelFile(metaModelCto, 'concerto.metamodel'); - return metaModelManager; -} + /** + * Validate against the metamodel + * @param {object} input - the metamodel in JSON + * @return {object} the validated metamodel in JSON + */ + static validateMetaModel(input) { + const metaModelManager = MetaModel.createMetaModelManager(); + const factory = new Factory(metaModelManager); + const serializer = new Serializer(factory, metaModelManager); + // First validate the metaModel + const object = serializer.fromJSON(input); + return serializer.toJSON(object); + } -/** - * Validate against the metamodel - * @param {object} input - the metamodel in JSON - * @return {object} the validated metamodel in JSON - */ -function validateMetaModel(input) { - const metaModelManager = createMetaModelManager(); - const factory = new Factory(metaModelManager); - const serializer = new Serializer(factory, metaModelManager); - // First validate the metaModel - const object = serializer.fromJSON(input); - return serializer.toJSON(object); -} + /** + * Create a name resolution table + * @param {*} modelManager - the model manager + * @param {object} metaModel - the metamodel (JSON) + * @return {object} mapping from a name to its namespace + */ + static createNameTable(modelManager, metaModel) { + const table = { + 'Concept': 'concerto', + 'Asset': 'concerto', + 'Participant': 'concerto', + 'Transaction ': 'concerto', + 'Event': 'concerto', + }; -/** - * Create a name resolution table - * @param {*} modelManager - the model manager - * @param {object} metaModel - the metamodel (JSON) - * @return {object} mapping from a name to its namespace - */ -function createNameTable(modelManager, metaModel) { - const table = { - 'Concept': 'concerto', - 'Asset': 'concerto', - 'Participant': 'concerto', - 'Transaction ': 'concerto', - 'Event': 'concerto', - }; - - // First list the imported names in order (overriding as we go along) - const imports = metaModel.imports; - imports.forEach((imp) => { - const namespace = imp.namespace; - const modelFile = modelManager.getModelFile(namespace); - if (imp.$class === 'concerto.metamodel.ImportType') { - if (!modelFile.getLocalType(imp.name)) { - throw new Error(`Declaration ${imp.name} in namespace ${namespace} not found`); + // First list the imported names in order (overriding as we go along) + const imports = metaModel.imports; + imports.forEach((imp) => { + const namespace = imp.namespace; + const modelFile = modelManager.getModelFile(namespace); + if (imp.$class === 'concerto.metamodel.ImportType') { + if (!modelFile.getLocalType(imp.name)) { + throw new Error(`Declaration ${imp.name} in namespace ${namespace} not found`); + } + table[imp.name] = namespace; + } else { + const decls = modelFile.getAllDeclarations(); + decls.forEach((decl) => { + table[decl.getName()] = namespace; + }); } - table[imp.name] = namespace; - } else { - const decls = modelFile.getAllDeclarations(); - decls.forEach((decl) => { - table[decl.getName()] = namespace; + }); + + // Then add the names local to this metaModel (overriding as we go along) + if (metaModel.declarations) { + metaModel.declarations.forEach((decl) => { + table[decl.name] = metaModel.namespace; }); } - }); - // Then add the names local to this metaModel (overriding as we go along) - if (metaModel.declarations) { - metaModel.declarations.forEach((decl) => { - table[decl.name] = metaModel.namespace; - }); + return table; } - return table; -} - -/** - * Resolve a name using the name table - * @param {string} name - the name of the type to resolve - * @param {object} table - the name table - * @return {string} the namespace for that name - */ -function resolveName(name, table) { - if (!table[name]) { - throw new Error(`Name ${name} not found`); + /** + * Resolve a name using the name table + * @param {string} name - the name of the type to resolve + * @param {object} table - the name table + * @return {string} the namespace for that name + */ + static resolveName(name, table) { + if (!table[name]) { + throw new Error(`Name ${name} not found`); + } + return table[name]; } - return table[name]; -} -/** - * Name resolution for metamodel - * @param {object} metaModel - the metamodel (JSON) - * @param {object} table - the name table - * @return {object} the metamodel with fully qualified names - */ -function resolveTypeNames(metaModel, table) { - switch (metaModel.$class) { - case 'concerto.metamodel.Model': { - if (metaModel.declarations) { - metaModel.declarations.forEach((decl) => { - resolveTypeNames(decl, table); + /** + * Name resolution for metamodel + * @param {object} metaModel - the metamodel (JSON) + * @param {object} table - the name table + * @return {object} the metamodel with fully qualified names + */ + static resolveTypeNames(metaModel, table) { + switch (metaModel.$class) { + case 'concerto.metamodel.Model': { + if (metaModel.declarations) { + metaModel.declarations.forEach((decl) => { + MetaModel.resolveTypeNames(decl, table); + }); + } + } + break; + case 'concerto.metamodel.AssetDeclaration': + case 'concerto.metamodel.ConceptDeclaration': + case 'concerto.metamodel.EventDeclaration': + case 'concerto.metamodel.TransactionDeclaration': + case 'concerto.metamodel.ParticipantDeclaration': { + if (metaModel.superType) { + const name = metaModel.superType.name; + metaModel.superType.namespace = MetaModel.resolveName(name, table); + } + metaModel.properties.forEach((property) => { + MetaModel.resolveTypeNames(property, table); }); + if (metaModel.decorators) { + metaModel.decorators.forEach((decorator) => { + MetaModel.resolveTypeNames(decorator, table); + }); + } } - } - break; - case 'concerto.metamodel.AssetDeclaration': - case 'concerto.metamodel.ConceptDeclaration': - case 'concerto.metamodel.EventDeclaration': - case 'concerto.metamodel.TransactionDeclaration': - case 'concerto.metamodel.ParticipantDeclaration': { - if (metaModel.superType) { - const name = metaModel.superType.name; - metaModel.superType.namespace = resolveName(name, table); + break; + case 'concerto.metamodel.EnumDeclaration': { + if (metaModel.decorators) { + metaModel.decorators.forEach((decorator) => { + MetaModel.resolveTypeNames(decorator, table); + }); + } } - metaModel.properties.forEach((property) => { - resolveTypeNames(property, table); - }); - if (metaModel.decorators) { - metaModel.decorators.forEach((decorator) => { - resolveTypeNames(decorator, table); - }); + break; + case 'concerto.metamodel.EnumProperty': + case 'concerto.metamodel.ObjectProperty': + case 'concerto.metamodel.RelationshipProperty': { + const name = metaModel.type.name; + metaModel.type.namespace = MetaModel.resolveName(name, table); + if (metaModel.decorators) { + metaModel.decorators.forEach((decorator) => { + MetaModel.resolveTypeNames(decorator, table); + }); + } } - } - break; - case 'concerto.metamodel.EnumDeclaration': { - if (metaModel.decorators) { - metaModel.decorators.forEach((decorator) => { - resolveTypeNames(decorator, table); - }); + break; + case 'concerto.metamodel.Decorator': { + if (metaModel.arguments) { + metaModel.arguments.forEach((argument) => { + MetaModel.resolveTypeNames(argument, table); + }); + } } - } - break; - case 'concerto.metamodel.EnumProperty': - case 'concerto.metamodel.ObjectProperty': - case 'concerto.metamodel.RelationshipProperty': { - const name = metaModel.type.name; - metaModel.type.namespace = resolveName(name, table); - if (metaModel.decorators) { - metaModel.decorators.forEach((decorator) => { - resolveTypeNames(decorator, table); - }); + break; + case 'concerto.metamodel.DecoratorTypeReference': { + const name = metaModel.type.name; + metaModel.type.namespace = MetaModel.resolveName(name, table); } - } - break; - case 'concerto.metamodel.Decorator': { - if (metaModel.arguments) { - metaModel.arguments.forEach((argument) => { - resolveTypeNames(argument, table); - }); + break; } + return metaModel; } - break; - case 'concerto.metamodel.DecoratorTypeReference': { - const name = metaModel.type.name; - metaModel.type.namespace = resolveName(name, table); - } - break; + + /** + * Resolve the namespace for names in the metamodel + * @param {object} modelManager - the ModelManager + * @param {object} metaModel - the MetaModel + * @return {object} the resolved metamodel + */ + static resolveMetaModel(modelManager, metaModel) { + const result = JSON.parse(JSON.stringify(metaModel)); + const nameTable = MetaModel.createNameTable(modelManager, metaModel); + // This adds the fully qualified names to the same object + MetaModel.resolveTypeNames(result, nameTable); + return result; } - return metaModel; -} -/** - * Resolve the namespace for names in the metamodel - * @param {object} modelManager - the ModelManager - * @param {object} metaModel - the MetaModel - * @return {object} the resolved metamodel - */ -function resolveMetaModel(modelManager, metaModel) { - const result = JSON.parse(JSON.stringify(metaModel)); - const nameTable = createNameTable(modelManager, metaModel); - // This adds the fully qualified names to the same object - resolveTypeNames(result, nameTable); - return result; -} + /** + * Create metamodel for an enum property + * @param {object} ast - the AST for the property + * @return {object} the metamodel for this property + */ + static enumPropertyToMetaModel(ast) { + const property = {}; -/** - * Create metamodel for an enum property - * @param {object} ast - the AST for the property - * @return {object} the metamodel for this property - */ -function enumPropertyToMetaModel(ast) { - const property = {}; + property.$class = 'concerto.metamodel.EnumProperty'; - property.$class = 'concerto.metamodel.EnumProperty'; + // Property name + property.name = ast.id.name; - // Property name - property.name = ast.id.name; + return property; + } - return property; -} + /** + * Create metamodel for a decorator argument + * @param {object} ast - the AST for the decorator argument + * @return {object} the metamodel for this decorator argument + */ + static decoratorArgToMetaModel(ast) { + const decoratorArg = {}; + switch (ast.type) { + case 'String': + decoratorArg.$class = 'concerto.metamodel.DecoratorString'; + decoratorArg.value = ast.value; + break; + case 'Number': + decoratorArg.$class = 'concerto.metamodel.DecoratorNumber'; + decoratorArg.value = ast.value; + break; + case 'Boolean': + decoratorArg.$class = 'concerto.metamodel.DecoratorBoolean'; + decoratorArg.value = ast.value; + break; + default: + decoratorArg.$class = 'concerto.metamodel.DecoratorTypeReference'; + decoratorArg.type = { + $class: 'concerto.metamodel.TypeIdentifier', + name: ast.value.name, + }; + decoratorArg.isArray = ast.value.array; + break; + } -/** - * Create metamodel for a decorator argument - * @param {object} ast - the AST for the decorator argument - * @return {object} the metamodel for this decorator argument - */ -function decoratorArgToMetaModel(ast) { - const decoratorArg = {}; - switch (ast.type) { - case 'String': - decoratorArg.$class = 'concerto.metamodel.DecoratorString'; - decoratorArg.value = ast.value; - break; - case 'Number': - decoratorArg.$class = 'concerto.metamodel.DecoratorNumber'; - decoratorArg.value = ast.value; - break; - case 'Boolean': - decoratorArg.$class = 'concerto.metamodel.DecoratorBoolean'; - decoratorArg.value = ast.value; - break; - default: - decoratorArg.$class = 'concerto.metamodel.DecoratorTypeReference'; - decoratorArg.type = { - $class: 'concerto.metamodel.TypeIdentifier', - name: ast.value.name, - }; - decoratorArg.isArray = ast.value.array; - break; + return decoratorArg; } - return decoratorArg; -} - -/** - * Create metamodel for a decorator - * @param {object} ast - the AST for the decorator - * @return {object} the metamodel for this decorator - */ -function decoratorToMetaModel(ast) { - const decorator = { - $class: 'concerto.metamodel.Decorator', - name: ast.name, - }; - if (ast.arguments && ast.arguments.list) { - if (!ast.arguments.list[0]) { - decorator.arguments = []; - } else { - decorator.arguments = ast.arguments.list.map(decoratorArgToMetaModel); + /** + * Create metamodel for a decorator + * @param {object} ast - the AST for the decorator + * @return {object} the metamodel for this decorator + */ + static decoratorToMetaModel(ast) { + const decorator = { + $class: 'concerto.metamodel.Decorator', + name: ast.name, + }; + if (ast.arguments && ast.arguments.list) { + if (!ast.arguments.list[0]) { + decorator.arguments = []; + } else { + decorator.arguments = ast.arguments.list.map(MetaModel.decoratorArgToMetaModel); + } } + return decorator; } - return decorator; -} - -/** - * Create metamodel for a list of decorators - * @param {object} ast - the AST for the decorators - * @return {object} the metamodel for the decorators - */ -function decoratorsToMetaModel(ast) { - return ast.map(decoratorToMetaModel); -} -/** - * Create metamodel for a property - * @param {object} ast - the AST for the property - * @return {object} the metamodel for this property - */ -function propertyToMetaModel(ast) { - const property = {}; - - // Property name - property.name = ast.id.name; - // Is it an array? - if (ast.array) { - property.isArray = true; - } else { - property.isArray = false; + /** + * Create metamodel for a list of decorators + * @param {object} ast - the AST for the decorators + * @return {object} the metamodel for the decorators + */ + static decoratorsToMetaModel(ast) { + return ast.map(MetaModel.decoratorToMetaModel); } - // Is it an optional? - if (ast.optional) { - property.isOptional = true; - } else { - property.isOptional = false; - } - // XXX Can it be missing? - const type = ast.propertyType.name; - // Handle decorators - if (ast.decorators && ast.decorators.length > 0) { - property.decorators = decoratorsToMetaModel(ast.decorators); - } + /** + * Create metamodel for a property + * @param {object} ast - the AST for the property + * @return {object} the metamodel for this property + */ + static propertyToMetaModel(ast) { + const property = {}; + + // Property name + property.name = ast.id.name; + // Is it an array? + if (ast.array) { + property.isArray = true; + } else { + property.isArray = false; + } + // Is it an optional? + if (ast.optional) { + property.isOptional = true; + } else { + property.isOptional = false; + } + // XXX Can it be missing? + const type = ast.propertyType.name; - switch (type) { - case 'Integer': - property.$class = 'concerto.metamodel.IntegerProperty'; - if (ast.default) { - property.defaultValue = parseInt(ast.default); + // Handle decorators + if (ast.decorators && ast.decorators.length > 0) { + property.decorators = MetaModel.decoratorsToMetaModel(ast.decorators); } - if (ast.range) { - const validator = { - $class: 'concerto.metamodel.IntegerDomainValidator', - }; - if (ast.range.lower) { - validator.lower = parseInt(ast.range.lower); + + switch (type) { + case 'Integer': + property.$class = 'concerto.metamodel.IntegerProperty'; + if (ast.default) { + property.defaultValue = parseInt(ast.default); } - if (ast.range.upper) { - validator.upper = parseInt(ast.range.upper); + if (ast.range) { + const validator = { + $class: 'concerto.metamodel.IntegerDomainValidator', + }; + if (ast.range.lower) { + validator.lower = parseInt(ast.range.lower); + } + if (ast.range.upper) { + validator.upper = parseInt(ast.range.upper); + } + property.validator = validator; } - property.validator = validator; - } - break; - case 'Long': - property.$class = 'concerto.metamodel.LongProperty'; - if (ast.default) { - property.defaultValue = parseInt(ast.default); - } - if (ast.range) { - const validator = { - $class: 'concerto.metamodel.LongDomainValidator', - }; - if (ast.range.lower) { - validator.lower = parseInt(ast.range.lower); + break; + case 'Long': + property.$class = 'concerto.metamodel.LongProperty'; + if (ast.default) { + property.defaultValue = parseInt(ast.default); } - if (ast.range.upper) { - validator.upper = parseInt(ast.range.upper); + if (ast.range) { + const validator = { + $class: 'concerto.metamodel.LongDomainValidator', + }; + if (ast.range.lower) { + validator.lower = parseInt(ast.range.lower); + } + if (ast.range.upper) { + validator.upper = parseInt(ast.range.upper); + } + property.validator = validator; } - property.validator = validator; - } - break; - case 'Double': - property.$class = 'concerto.metamodel.DoubleProperty'; - if (ast.default) { - property.defaultValue = parseFloat(ast.default); - } - if (ast.range) { - const validator = { - $class: 'concerto.metamodel.DoubleDomainValidator', - }; - if (ast.range.lower) { - validator.lower = parseFloat(ast.range.lower); + break; + case 'Double': + property.$class = 'concerto.metamodel.DoubleProperty'; + if (ast.default) { + property.defaultValue = parseFloat(ast.default); } - if (ast.range.upper) { - validator.upper = parseFloat(ast.range.upper); + if (ast.range) { + const validator = { + $class: 'concerto.metamodel.DoubleDomainValidator', + }; + if (ast.range.lower) { + validator.lower = parseFloat(ast.range.lower); + } + if (ast.range.upper) { + validator.upper = parseFloat(ast.range.upper); + } + property.validator = validator; } - property.validator = validator; - } - break; - case 'Boolean': - property.$class = 'concerto.metamodel.BooleanProperty'; - if (ast.default) { - if (ast.default === 'true') { - property.defaultValue = true; - } else { - property.defaultValue = false; + break; + case 'Boolean': + property.$class = 'concerto.metamodel.BooleanProperty'; + if (ast.default) { + if (ast.default === 'true') { + property.defaultValue = true; + } else { + property.defaultValue = false; + } } - } - break; - case 'DateTime': - property.$class = 'concerto.metamodel.DateTimeProperty'; - break; - case 'String': - property.$class = 'concerto.metamodel.StringProperty'; - if (ast.default) { - property.defaultValue = ast.default; - } - if (ast.regex) { - const regex = ast.regex.flags ? `/${ast.regex.pattern}/${ast.regex.flags}` : `/${ast.regex.pattern}/}`; - property.validator = { - $class: 'concerto.metamodel.StringRegexValidator', - regex, + break; + case 'DateTime': + property.$class = 'concerto.metamodel.DateTimeProperty'; + break; + case 'String': + property.$class = 'concerto.metamodel.StringProperty'; + if (ast.default) { + property.defaultValue = ast.default; + } + if (ast.regex) { + const regex = ast.regex.flags ? `/${ast.regex.pattern}/${ast.regex.flags}` : `/${ast.regex.pattern}/}`; + property.validator = { + $class: 'concerto.metamodel.StringRegexValidator', + regex, + }; + } + break; + default: + property.$class = 'concerto.metamodel.ObjectProperty'; + if (ast.default) { + property.defaultValue = ast.default; + } + property.type = { + $class: 'concerto.metamodel.TypeIdentifier', + name: type }; + break; } - break; - default: - property.$class = 'concerto.metamodel.ObjectProperty'; - if (ast.default) { - property.defaultValue = ast.default; - } - property.type = { - $class: 'concerto.metamodel.TypeIdentifier', - name: type - }; - break; + + return property; } - return property; -} + /** + * Create metamodel for a relationship + * @param {object} ast - the AST for the relationtion + * @return {object} the metamodel for this relationship + */ + static relationshipToMetaModel(ast) { + let relationship = { + $class: 'concerto.metamodel.RelationshipProperty', + type: { + $class: 'concerto.metamodel.TypeIdentifier', + name: ast.propertyType.name + }, + }; -/** - * Create metamodel for a relationship - * @param {object} ast - the AST for the relationtion - * @return {object} the metamodel for this relationship - */ -function relationshipToMetaModel(ast) { - let relationship = { - $class: 'concerto.metamodel.RelationshipProperty', - type: { - $class: 'concerto.metamodel.TypeIdentifier', - name: ast.propertyType.name - }, - }; - - // Property name - relationship.name = ast.id.name; - // Is it an array? - if (ast.array) { - relationship.isArray = true; - } else { - relationship.isArray = false; - } - // Is it an optional? - if (ast.optional) { - relationship.isOptional = true; - } else { - relationship.isOptional = false; + // Property name + relationship.name = ast.id.name; + // Is it an array? + if (ast.array) { + relationship.isArray = true; + } else { + relationship.isArray = false; + } + // Is it an optional? + if (ast.optional) { + relationship.isOptional = true; + } else { + relationship.isOptional = false; + } + + return relationship; } - return relationship; -} + /** + * Create metamodel for an enum declaration + * @param {object} ast - the AST for the enum declaration + * @return {object} the metamodel for this enum declaration + */ + static enumDeclToMetaModel(ast) { + let decl = {}; -/** - * Create metamodel for an enum declaration - * @param {object} ast - the AST for the enum declaration - * @return {object} the metamodel for this enum declaration - */ -function enumDeclToMetaModel(ast) { - let decl = {}; + decl.$class = 'concerto.metamodel.EnumDeclaration'; - decl.$class = 'concerto.metamodel.EnumDeclaration'; + // The enum name + decl.name = ast.id.name; - // The enum name - decl.name = ast.id.name; + // Enum properties + decl.properties = []; + for (let n = 0; n < ast.body.declarations.length; n++) { + let thing = ast.body.declarations[n]; - // Enum properties - decl.properties = []; - for (let n = 0; n < ast.body.declarations.length; n++) { - let thing = ast.body.declarations[n]; + decl.properties.push(MetaModel.enumPropertyToMetaModel(thing)); + } - decl.properties.push(enumPropertyToMetaModel(thing)); + return decl; } - return decl; -} - -/** - * Create metamodel for a concept declaration - * @param {object} ast - the AST for the concept declaration - * @return {object} the metamodel for this concept declaration - */ -function conceptDeclToMetaModel(ast) { - let decl = {}; - - if(ast.type === 'AssetDeclaration') { - decl.$class = 'concerto.metamodel.AssetDeclaration'; - } else if (ast.type === 'ConceptDeclaration') { - decl.$class = 'concerto.metamodel.ConceptDeclaration'; - } else if (ast.type === 'EventDeclaration') { - decl.$class = 'concerto.metamodel.EventDeclaration'; - } else if (ast.type === 'ParticipantDeclaration') { - decl.$class = 'concerto.metamodel.ParticipantDeclaration'; - } else if (ast.type === 'TransactionDeclaration') { - decl.$class = 'concerto.metamodel.TransactionDeclaration'; - } + /** + * Create metamodel for a concept declaration + * @param {object} ast - the AST for the concept declaration + * @return {object} the metamodel for this concept declaration + */ + static conceptDeclToMetaModel(ast) { + let decl = {}; + + if(ast.type === 'AssetDeclaration') { + decl.$class = 'concerto.metamodel.AssetDeclaration'; + } else if (ast.type === 'ConceptDeclaration') { + decl.$class = 'concerto.metamodel.ConceptDeclaration'; + } else if (ast.type === 'EventDeclaration') { + decl.$class = 'concerto.metamodel.EventDeclaration'; + } else if (ast.type === 'ParticipantDeclaration') { + decl.$class = 'concerto.metamodel.ParticipantDeclaration'; + } else if (ast.type === 'TransactionDeclaration') { + decl.$class = 'concerto.metamodel.TransactionDeclaration'; + } - // The concept name - decl.name = ast.id.name; + // The concept name + decl.name = ast.id.name; - // Is the concept abstract? - if (ast.abstract) { - decl.isAbstract = true; - } else { - decl.isAbstract = false; - } + // Is the concept abstract? + if (ast.abstract) { + decl.isAbstract = true; + } else { + decl.isAbstract = false; + } - // Super type - if (ast.classExtension) { - const cname = ast.classExtension.class.name; - if (cname !== 'Asset' && + // Super type + if (ast.classExtension) { + const cname = ast.classExtension.class.name; + if (cname !== 'Asset' && cname !== 'Concept' && cname !== 'Event' && cname !== 'Participant' && cname !== 'Transaction') { - decl.superType = { - $class: 'concerto.metamodel.TypeIdentifier', - name: ast.classExtension.class.name - }; + decl.superType = { + $class: 'concerto.metamodel.TypeIdentifier', + name: ast.classExtension.class.name + }; + } } - } - // Is the concept idenfitied by a property - if (ast.idField) { - if (ast.idField.name === '$identifier') { - decl.identified = { - $class: 'concerto.metamodel.Identified' - }; - } else { - decl.identified = { - $class: 'concerto.metamodel.IdentifiedBy', - name: ast.idField.name - }; + // Is the concept idenfitied by a property + if (ast.idField) { + if (ast.idField.name === '$identifier') { + decl.identified = { + $class: 'concerto.metamodel.Identified' + }; + } else { + decl.identified = { + $class: 'concerto.metamodel.IdentifiedBy', + name: ast.idField.name + }; + } } - } - // Handle decorators - if (ast.decorators && ast.decorators.length > 0) { - decl.decorators = decoratorsToMetaModel(ast.decorators); + // Handle decorators + if (ast.decorators && ast.decorators.length > 0) { + decl.decorators = MetaModel.decoratorsToMetaModel(ast.decorators); + } + + // Concept properties + decl.properties = []; + for (let n = 0; n < ast.body.declarations.length; n++) { + let thing = ast.body.declarations[n]; + // console.log(`THING ${JSON.stringify(thing)}`); + if (thing.type === 'FieldDeclaration') { + decl.properties.push(MetaModel.propertyToMetaModel(thing)); + } else if (thing.type === 'RelationshipDeclaration') { + decl.properties.push(MetaModel.relationshipToMetaModel(thing)); + } + } + + return decl; } - // Concept properties - decl.properties = []; - for (let n = 0; n < ast.body.declarations.length; n++) { - let thing = ast.body.declarations[n]; - // console.log(`THING ${JSON.stringify(thing)}`); - if (thing.type === 'FieldDeclaration') { - decl.properties.push(propertyToMetaModel(thing)); - } else if (thing.type === 'RelationshipDeclaration') { - decl.properties.push(relationshipToMetaModel(thing)); + /** + * Create metamodel for a declaration + * @param {object} ast - the AST for the declaration + * @return {object} the metamodel for this declaration + */ + static declToMetaModel(ast) { + if(ast.type === 'EnumDeclaration') { + return MetaModel.enumDeclToMetaModel(ast); } + return MetaModel.conceptDeclToMetaModel(ast); } - return decl; -} + /** + * Export metamodel from an AST + * @param {object} ast - the AST for the model + * @param {boolean} [validate] - whether to perform validation + * @return {object} the metamodel for this model + */ + static modelToMetaModel(ast, validate = true) { + const metamodel = { + $class: 'concerto.metamodel.Model' + }; + metamodel.namespace = ast.namespace; + + if(ast.imports) { + metamodel.imports = []; + ast.imports.forEach((imp) => { + const split = imp.namespace.split('.'); + const name = split.pop(); + const namespace = split.join('.'); + if (namespace === 'concerto') { + return; + } + const ns = { namespace }; + if (name === '*') { + ns.$class = 'concerto.metamodel.ImportAll'; + } else { + ns.$class = 'concerto.metamodel.ImportType'; + ns.name = name; + } + if(imp.uri) { + ns.uri = imp.uri; + } + metamodel.imports.push(ns); + }); + } -/** - * Create metamodel for a declaration - * @param {object} ast - the AST for the declaration - * @return {object} the metamodel for this declaration - */ -function declToMetaModel(ast) { - if(ast.type === 'EnumDeclaration') { - return enumDeclToMetaModel(ast); + if (ast.body.length > 0) { + metamodel.declarations = []; + } + for(let n=0; n < ast.body.length; n++ ) { + const thing = ast.body[n]; + const decl = MetaModel.declToMetaModel(thing); + metamodel.declarations.push(decl); + } + + // Last, validate the JSON metaModel + const mm = validate ? MetaModel.validateMetaModel(metamodel) : metamodel; + + return mm; } - return conceptDeclToMetaModel(ast); -} -/** - * Export metamodel from an AST - * @param {object} ast - the AST for the model - * @param {boolean} [validate] - whether to perform validation - * @return {object} the metamodel for this model - */ -function modelToMetaModel(ast, validate = true) { - const metamodel = { - $class: 'concerto.metamodel.Model' - }; - metamodel.namespace = ast.namespace; - - if(ast.imports) { - metamodel.imports = []; - ast.imports.forEach((imp) => { - const split = imp.namespace.split('.'); - const name = split.pop(); - const namespace = split.join('.'); - if (namespace === 'concerto') { - return; - } - const ns = { namespace }; - if (name === '*') { - ns.$class = 'concerto.metamodel.ImportAll'; - } else { - ns.$class = 'concerto.metamodel.ImportType'; - ns.name = name; - } - if(imp.uri) { - ns.uri = imp.uri; + /** + * Export metamodel from a model file + * @param {object} modelFile - the ModelFile + * @param {boolean} [validate] - whether to perform validation + * @return {object} the metamodel for this model + */ + static modelFileToMetaModel(modelFile, validate) { + return MetaModel.modelToMetaModel(modelFile.ast, validate); + } + + /** + * Export metamodel from a model manager + * @param {object} modelManager - the ModelManager + * @param {boolean} [resolve] - whether to resolve names + * @param {boolean} [validate] - whether to perform validation + * @return {object} the metamodel for this model manager + */ + static modelManagerToMetaModel(modelManager, resolve, validate) { + const result = { + $class: 'concerto.metamodel.Models', + models: [], + }; + modelManager.getModelFiles().forEach((modelFile) => { + let metaModel = MetaModel.modelToMetaModel(modelFile.ast, validate); + if (resolve) { + metaModel = MetaModel.resolveMetaModel(modelManager, metaModel); } - metamodel.imports.push(ns); + result.models.push(metaModel); }); + return result; } - if (ast.body.length > 0) { - metamodel.declarations = []; - } - for(let n=0; n < ast.body.length; n++ ) { - const thing = ast.body[n]; - const decl = declToMetaModel(thing); - metamodel.declarations.push(decl); + /** + * Create decorator argument string from a metamodel + * @param {object} mm - the metamodel + * @return {string} the string for the decorator argument + */ + static decoratorArgFromMetaModel(mm) { + let result = ''; + switch (mm.$class) { + case 'concerto.metamodel.DecoratorTypeReference': + result += `${mm.type.name}${mm.isArray ? '[]' : ''}`; + break; + case 'concerto.metamodel.DecoratorString': + result += `"${mm.value}"`; + break; + default: + result += `${mm.value}`; + break; + } + return result; } - // Last, validate the JSON metaModel - const mm = validate ? validateMetaModel(metamodel) : metamodel; - - return mm; -} - -/** - * Export metamodel from a model file - * @param {object} modelFile - the ModelFile - * @param {boolean} [validate] - whether to perform validation - * @return {object} the metamodel for this model - */ -function modelFileToMetaModel(modelFile, validate) { - return modelToMetaModel(modelFile.ast, validate); -} - -/** - * Export metamodel from a model manager - * @param {object} modelManager - the ModelManager - * @param {boolean} [resolve] - whether to resolve names - * @param {boolean} [validate] - whether to perform validation - * @return {object} the metamodel for this model manager - */ -function modelManagerToMetaModel(modelManager, resolve, validate) { - const result = { - $class: 'concerto.metamodel.Models', - models: [], - }; - modelManager.getModelFiles().forEach((modelFile) => { - let metaModel = modelToMetaModel(modelFile.ast, validate); - if (resolve) { - metaModel = resolveMetaModel(modelManager, metaModel); + /** + * Create decorator string from a metamodel + * @param {object} mm - the metamodel + * @return {string} the string for the decorator + */ + static decoratorFromMetaModel(mm) { + let result = ''; + result += `@${mm.name}`; + if (mm.arguments) { + result += '('; + result += mm.arguments.map(MetaModel.decoratorArgFromMetaModel).join(','); + result += ')'; } - result.models.push(metaModel); - }); - return result; -} - -/** - * Create decorator argument string from a metamodel - * @param {object} mm - the metamodel - * @return {string} the string for the decorator argument - */ -function decoratorArgFromMetaModel(mm) { - let result = ''; - switch (mm.$class) { - case 'concerto.metamodel.DecoratorTypeReference': - result += `${mm.type.name}${mm.isArray ? '[]' : ''}`; - break; - case 'concerto.metamodel.DecoratorString': - result += `"${mm.value}"`; - break; - default: - result += `${mm.value}`; - break; + return result; } - return result; -} -/** - * Create decorator string from a metamodel - * @param {object} mm - the metamodel - * @return {string} the string for the decorator - */ -function decoratorFromMetaModel(mm) { - let result = ''; - result += `@${mm.name}`; - if (mm.arguments) { - result += '('; - result += mm.arguments.map(decoratorArgFromMetaModel).join(','); - result += ')'; + /** + * Create decorators string from a metamodel + * @param {object} mm - the metamodel + * @param {string} prefix - indentation + * @return {string} the string for the decorators + */ + static decoratorsFromMetaModel(mm, prefix) { + let result = ''; + result += mm.map(MetaModel.decoratorFromMetaModel).join(`\n${prefix}`); + result += `\n${prefix}`; + return result; } - return result; -} - -/** - * Create decorators string from a metamodel - * @param {object} mm - the metamodel - * @param {string} prefix - indentation - * @return {string} the string for the decorators - */ -function decoratorsFromMetaModel(mm, prefix) { - let result = ''; - result += mm.map(decoratorFromMetaModel).join(`\n${prefix}`); - result += `\n${prefix}`; - return result; -} -/** - * Create a property string from a metamodel - * @param {object} mm - the metamodel - * @return {string} the string for that property - */ -function propertyFromMetaModel(mm) { - let result = ''; - let defaultString = ''; - let validatorString = ''; + /** + * Create a property string from a metamodel + * @param {object} mm - the metamodel + * @return {string} the string for that property + */ + static propertyFromMetaModel(mm) { + let result = ''; + let defaultString = ''; + let validatorString = ''; + + if (mm.decorators) { + result += MetaModel.decoratorsFromMetaModel(mm.decorators, ' '); + } + if (mm.$class === 'concerto.metamodel.RelationshipProperty') { + result += '-->'; + } else { + result += 'o'; + } - if (mm.decorators) { - result += decoratorsFromMetaModel(mm.decorators, ' '); - } - if (mm.$class === 'concerto.metamodel.RelationshipProperty') { - result += '-->'; - } else { - result += 'o'; - } + switch (mm.$class) { + case 'concerto.metamodel.EnumProperty': + break; + case 'concerto.metamodel.BooleanProperty': + result += ' Boolean'; + if (mm.defaultValue === true || mm.defaultValue === false) { + if (mm.defaultValue) { + defaultString += ' default=true'; + } else { + defaultString += ' default=false'; + } + } + break; + case 'concerto.metamodel.DateTimeProperty': + result += ' DateTime'; + break; + case 'concerto.metamodel.DoubleProperty': + result += ' Double'; + if (mm.defaultValue) { + const doubleString = mm.defaultValue.toFixed(Math.max(1, (mm.defaultValue.toString().split('.')[1] || []).length)); - switch (mm.$class) { - case 'concerto.metamodel.EnumProperty': - break; - case 'concerto.metamodel.BooleanProperty': - result += ' Boolean'; - if (mm.defaultValue === true || mm.defaultValue === false) { + defaultString += ` default=${doubleString}`; + } + if (mm.validator) { + const lowerString = mm.validator.lower ? mm.validator.lower : ''; + const upperString = mm.validator.upper ? mm.validator.upper : ''; + validatorString += ` range=[${lowerString},${upperString}]`; + } + break; + case 'concerto.metamodel.IntegerProperty': + result += ' Integer'; if (mm.defaultValue) { - defaultString += ' default=true'; - } else { - defaultString += ' default=false'; + defaultString += ` default=${mm.defaultValue.toString()}`; } + if (mm.validator) { + const lowerString = mm.validator.lower ? mm.validator.lower : ''; + const upperString = mm.validator.upper ? mm.validator.upper : ''; + validatorString += ` range=[${lowerString},${upperString}]`; + } + break; + case 'concerto.metamodel.LongProperty': + result += ' Long'; + if (mm.defaultValue) { + defaultString += ` default=${mm.defaultValue.toString()}`; + } + if (mm.validator) { + const lowerString = mm.validator.lower ? mm.validator.lower : ''; + const upperString = mm.validator.upper ? mm.validator.upper : ''; + validatorString += ` range=[${lowerString},${upperString}]`; + } + break; + case 'concerto.metamodel.StringProperty': + result += ' String'; + if (mm.defaultValue) { + defaultString += ` default="${mm.defaultValue}"`; + } + if (mm.validator) { + validatorString += ` regex=${mm.validator.regex}`; + } + break; + case 'concerto.metamodel.ObjectProperty': + result += ` ${mm.type.name}`; + if (mm.defaultValue) { + defaultString += ` default="${mm.defaultValue}"`; + } + break; + case 'concerto.metamodel.RelationshipProperty': + result += ` ${mm.type.name}`; + break; } - break; - case 'concerto.metamodel.DateTimeProperty': - result += ' DateTime'; - break; - case 'concerto.metamodel.DoubleProperty': - result += ' Double'; - if (mm.defaultValue) { - const doubleString = mm.defaultValue.toFixed(Math.max(1, (mm.defaultValue.toString().split('.')[1] || []).length)); - - defaultString += ` default=${doubleString}`; - } - if (mm.validator) { - const lowerString = mm.validator.lower ? mm.validator.lower : ''; - const upperString = mm.validator.upper ? mm.validator.upper : ''; - validatorString += ` range=[${lowerString},${upperString}]`; - } - break; - case 'concerto.metamodel.IntegerProperty': - result += ' Integer'; - if (mm.defaultValue) { - defaultString += ` default=${mm.defaultValue.toString()}`; + if (mm.isArray) { + result += '[]'; } - if (mm.validator) { - const lowerString = mm.validator.lower ? mm.validator.lower : ''; - const upperString = mm.validator.upper ? mm.validator.upper : ''; - validatorString += ` range=[${lowerString},${upperString}]`; + result += ` ${mm.name}`; + if (mm.isOptional) { + result += ' optional'; } - break; - case 'concerto.metamodel.LongProperty': - result += ' Long'; - if (mm.defaultValue) { - defaultString += ` default=${mm.defaultValue.toString()}`; + result += defaultString; + result += validatorString; + return result; + } + + /** + * Create a declaration string from a metamodel + * @param {object} mm - the metamodel + * @return {string} the string for that declaration + */ + static declFromMetaModel(mm) { + let result = ''; + if (mm.decorators) { + result += MetaModel.decoratorsFromMetaModel(mm.decorators, ''); } - if (mm.validator) { - const lowerString = mm.validator.lower ? mm.validator.lower : ''; - const upperString = mm.validator.upper ? mm.validator.upper : ''; - validatorString += ` range=[${lowerString},${upperString}]`; + + if (mm.isAbstract) { + result += 'abstract '; } - break; - case 'concerto.metamodel.StringProperty': - result += ' String'; - if (mm.defaultValue) { - defaultString += ` default="${mm.defaultValue}"`; + switch (mm.$class) { + case 'concerto.metamodel.AssetDeclaration': + result += `asset ${mm.name} `; + break; + case 'concerto.metamodel.ConceptDeclaration': + result += `concept ${mm.name} `; + break; + case 'concerto.metamodel.EventDeclaration': + result += `event ${mm.name} `; + break; + case 'concerto.metamodel.ParticipantDeclaration': + result += `participant ${mm.name} `; + break; + case 'concerto.metamodel.TransactionDeclaration': + result += `transaction ${mm.name} `; + break; + case 'concerto.metamodel.EnumDeclaration': + result += `enum ${mm.name} `; + break; } - if (mm.validator) { - validatorString += ` regex=${mm.validator.regex}`; + if (mm.superType) { + result += `extends ${mm.superType.name} `; } - break; - case 'concerto.metamodel.ObjectProperty': - result += ` ${mm.type.name}`; - if (mm.defaultValue) { - defaultString += ` default="${mm.defaultValue}"`; + // XXX Needs to be fixed to support `identified` + if (mm.identified) { + if (mm.identified.$class === 'concerto.metamodel.IdentifiedBy') { + result += `identified by ${mm.identified.name} `; + } else { + result += 'identified '; + } } - break; - case 'concerto.metamodel.RelationshipProperty': - result += ` ${mm.type.name}`; - break; - } - if (mm.isArray) { - result += '[]'; - } - result += ` ${mm.name}`; - if (mm.isOptional) { - result += ' optional'; - } - result += defaultString; - result += validatorString; - return result; -} - -/** - * Create a declaration string from a metamodel - * @param {object} mm - the metamodel - * @return {string} the string for that declaration - */ -function declFromMetaModel(mm) { - let result = ''; - if (mm.decorators) { - result += decoratorsFromMetaModel(mm.decorators, ''); + result += '{'; + mm.properties.forEach((property) => { + result += `\n ${MetaModel.propertyFromMetaModel(property)}`; + }); + result += '\n}'; + return result; } - if (mm.isAbstract) { - result += 'abstract '; - } - switch (mm.$class) { - case 'concerto.metamodel.AssetDeclaration': - result += `asset ${mm.name} `; - break; - case 'concerto.metamodel.ConceptDeclaration': - result += `concept ${mm.name} `; - break; - case 'concerto.metamodel.EventDeclaration': - result += `event ${mm.name} `; - break; - case 'concerto.metamodel.ParticipantDeclaration': - result += `participant ${mm.name} `; - break; - case 'concerto.metamodel.TransactionDeclaration': - result += `transaction ${mm.name} `; - break; - case 'concerto.metamodel.EnumDeclaration': - result += `enum ${mm.name} `; - break; - } - if (mm.superType) { - result += `extends ${mm.superType.name} `; - } - // XXX Needs to be fixed to support `identified` - if (mm.identified) { - if (mm.identified.$class === 'concerto.metamodel.IdentifiedBy') { - result += `identified by ${mm.identified.name} `; - } else { - result += 'identified '; + /** + * Create a model string from a metamodel + * @param {object} metaModel - the metamodel + * @param {boolean} [validate] - whether to perform validation + * @return {string} the string for that model + */ + static ctoFromMetaModel(metaModel, validate = true) { + // First, validate the JSON metaModel + const mm = validate ? MetaModel.validateMetaModel(metaModel) : metaModel; + + let result = ''; + result += `namespace ${mm.namespace}`; + if (mm.imports && mm.imports.length > 0) { + result += '\n'; + mm.imports.forEach((imp) => { + let name = '*'; + if (imp.$class === 'concerto.metamodel.ImportType') { + name = imp.name; + } + result += `\nimport ${imp.namespace}.${name}`; + if (imp.uri) { + result += ` from ${imp.uri}`; + } + }); + } + if (mm.declarations && mm.declarations.length > 0) { + mm.declarations.forEach((decl) => { + result += `\n\n${MetaModel.declFromMetaModel(decl)}`; + }); } + return result; } - result += '{'; - mm.properties.forEach((property) => { - result += `\n ${propertyFromMetaModel(property)}`; - }); - result += '\n}'; - return result; -} -/** - * Create a model string from a metamodel - * @param {object} metaModel - the metamodel - * @param {boolean} [validate] - whether to perform validation - * @return {string} the string for that model - */ -function ctoFromMetaModel(metaModel, validate = true) { - // First, validate the JSON metaModel - const mm = validate ? validateMetaModel(metaModel) : metaModel; - - let result = ''; - result += `namespace ${mm.namespace}`; - if (mm.imports && mm.imports.length > 0) { - result += '\n'; - mm.imports.forEach((imp) => { - let name = '*'; - if (imp.$class === 'concerto.metamodel.ImportType') { - name = imp.name; - } - result += `\nimport ${imp.namespace}.${name}`; - if (imp.uri) { - result += ` from ${imp.uri}`; - } - }); - } - if (mm.declarations && mm.declarations.length > 0) { - mm.declarations.forEach((decl) => { - result += `\n\n${declFromMetaModel(decl)}`; + /** + * Import metamodel to a model manager + * @param {object} metaModel - the metamodel + * @param {boolean} [validate] - whether to perform validation + * @return {object} the metamodel for this model manager + */ + static modelManagerFromMetaModel(metaModel, validate) { + // First, validate the JSON metaModel + const mm = validate ? MetaModel.validateMetaModel(metaModel) : metaModel; + + const modelManager = new ModelManager(); + + mm.models.forEach((mm) => { + const cto = MetaModel.ctoFromMetaModel(mm, false); // No need to re-validate + modelManager.addModelFile(cto, null, false); }); - } - return result; -} - -/** - * Import metamodel to a model manager - * @param {object} metaModel - the metamodel - * @param {boolean} [validate] - whether to perform validation - * @return {object} the metamodel for this model manager - */ -function modelManagerFromMetaModel(metaModel, validate) { - // First, validate the JSON metaModel - const mm = validate ? validateMetaModel(metaModel) : metaModel; - const modelManager = new ModelManager(); - - mm.models.forEach((mm) => { - const cto = ctoFromMetaModel(mm, false); // No need to re-validate - modelManager.addModelFile(cto, null, false); - }); - - modelManager.validateModelFiles(); - return modelManager; -} + modelManager.validateModelFiles(); + return modelManager; + } -/** - * Export metamodel from a model string - * @param {string} model - the string for the model - * @param {boolean} [validate] - whether to perform validation - * @return {object} the metamodel for this model - */ -function ctoToMetaModel(model, validate) { - const ast = parser.parse(model); - return modelToMetaModel(ast); -} + /** + * Export metamodel from a model string + * @param {string} model - the string for the model + * @param {boolean} [validate] - whether to perform validation + * @return {object} the metamodel for this model + */ + static ctoToMetaModel(model, validate) { + const ast = parser.parse(model); + return MetaModel.modelToMetaModel(ast); + } -/** - * Export metamodel from a model string and resolve names - * @param {*} modelManager - the model manager - * @param {string} model - the string for the model - * @param {boolean} [validate] - whether to perform validation - * @return {object} the metamodel for this model - */ -function ctoToMetaModelAndResolve(modelManager, model, validate) { - const ast = parser.parse(model); - const metaModel = modelToMetaModel(ast); - const result = resolveMetaModel(modelManager, metaModel); - return result; + /** + * Export metamodel from a model string and resolve names + * @param {*} modelManager - the model manager + * @param {string} model - the string for the model + * @param {boolean} [validate] - whether to perform validation + * @return {object} the metamodel for this model + */ + static ctoToMetaModelAndResolve(modelManager, model, validate) { + const ast = parser.parse(model); + const metaModel = MetaModel.modelToMetaModel(ast); + const result = MetaModel.resolveMetaModel(modelManager, metaModel); + return result; + } } -module.exports = { - metaModelCto, - modelFileToMetaModel, - modelManagerToMetaModel, - modelManagerFromMetaModel, - resolveMetaModel, - ctoToMetaModel, - ctoToMetaModelAndResolve, - ctoFromMetaModel, -}; +module.exports = MetaModel; diff --git a/packages/concerto-core/package.json b/packages/concerto-core/package.json index e927a68311..a448b667ac 100644 --- a/packages/concerto-core/package.json +++ b/packages/concerto-core/package.json @@ -35,13 +35,14 @@ "author": "accordproject.org", "license": "Apache-2.0", "devDependencies": { - "acorn": "5.1.2", + "acorn": "8.5.0", + "acorn-walk": "8.2.0", "chai": "4.3.4", "chai-as-promised": "7.1.1", "chai-things": "0.2.0", "commander": "2.20.0", "doctrine": "3.0.0", - "eslint": "7.24.0", + "eslint": "8.2.0", "fs-extra": "9.1.0", "jsdoc": "^3.6.7", "klaw": "3.0.0", diff --git a/packages/concerto-core/scripts/javascriptparser.js b/packages/concerto-core/scripts/javascriptparser.js index 0a1f85bbd6..456b654258 100644 --- a/packages/concerto-core/scripts/javascriptparser.js +++ b/packages/concerto-core/scripts/javascriptparser.js @@ -16,6 +16,7 @@ const doctrine = require('doctrine'); const acorn = require('acorn'); +const walk = require('acorn-walk'); /** * Processes a single Javascript file (.js extension) @@ -36,101 +37,55 @@ class JavaScriptParser { * @param {number} [ecmaVersion] - the ECMAScript version to use * @param {boolean} [engineMode] - true if being used by engine for TP/ACL function Parsing */ - constructor(fileContents, includePrivates, ecmaVersion, engineMode = true) { + constructor(fileContents, includePrivates, ecmaVersion) { let comments = []; this.tokens = []; + let nodesToProcess = []; + this.classes = []; + this.functions = []; + this.includes = []; - // If the magic flag is set, don't collect tokens. They eat up a lot of - // memory and this is problematic for the HLFv1 runtime (the only place - // that this flag is set). - let noTokens = !!global.composerJavaScriptParserNoTokens; - - let options = { - // collect ranges for each node - ranges: true, - // collect comments in Esprima's format - onComment: comments, - // collect token ranges - onToken: noTokens ? null : this.tokens, - // collect token locations - locations: true, - // locations: true, - plugins: { - 'composereof': true - } - }; - - - if (ecmaVersion) { - options.ecmaVersion = ecmaVersion; - } - - acorn.plugins.composereof = function (parser) { - - parser.extend('parseTopLevel', function (nextMethod) { - return function (node) { - let this$1 = this; - - let exports = {}; - if (!node.body) { - node.body = []; - } - while (this.type.label !== 'eof') { - let stmt = this$1.parseStatement(true, true, exports); - node.body.push(stmt); - } - this.next(); - if (this.options.ecmaVersion >= 6) { - node.sourceType = this.options.sourceType; - } - return this.finishNode(node, 'Program'); - }; + const onComment = (block, text, start, end, line, column) => { + comments.push({ + block, + text, + start, + end, + line, + column }); }; - let ast = acorn.parse(fileContents, options); - this.includes = []; - this.classes = []; - this.functions = []; - let nodesToProcess = ast.body; - - // engine mode only wants to look at the top level function definitions - // but the js doc generator wants to look at everything so this parser - // needs to handle both requirements. - if (!engineMode) { - nodesToProcess = []; - const walk = require('acorn/dist/walk'); - walk.simple(ast, { - FunctionDeclaration(node) { - if (node.id && node.id.name) { - nodesToProcess.push(node); - } - }, - FunctionExpression(node) { - if (node.id && node.id.name) { - nodesToProcess.push(node); - } - }, - ClassDeclaration(node) { + const ast = acorn.parse(fileContents, {ecmaVersion, locations:true, onComment}); + + nodesToProcess = []; + walk.simple(ast, { + FunctionDeclaration(node) { + if (node.id && node.id.name) { nodesToProcess.push(node); } - }); - } + }, + FunctionExpression(node) { + if (node.id && node.id.name) { + nodesToProcess.push(node); + } + }, + ClassDeclaration(node) { + nodesToProcess.push(node); + }, + VariableDeclaration(node) { + nodesToProcess.push(node); + } + }); for (let n = 0; n < nodesToProcess.length; n++) { - let statement = nodesToProcess[n]; - - // record the end of the previous node, required for engineMode only - let previousEnd = -1; - if (n !== 0) { - previousEnd = nodesToProcess[n - 1].end; - } + const statement = nodesToProcess[n]; if (statement.type === 'VariableDeclaration') { - let variableDeclarations = statement.declarations; + const variableDeclarations = statement.declarations; for (let n = 0; n < variableDeclarations.length; n++) { - let variableDeclaration = variableDeclarations[n]; + const variableDeclaration = variableDeclarations[n]; if (variableDeclaration.init && variableDeclaration.init.type === 'CallExpression' && variableDeclaration.init.callee.name === 'require') { @@ -141,14 +96,8 @@ class JavaScriptParser { } } } - } else if (statement.type === 'FunctionDeclaration' || (statement.type === 'FunctionExpression' && !engineMode)) { - let closestComment; - // different approaches to finding comments depending on mode as they are not compatible. - if (!engineMode) { - closestComment = JavaScriptParser.findCommentBefore(comments, statement.loc.start.line); - } else { - closestComment = JavaScriptParser.searchForComment(statement.start, statement.end, previousEnd, comments); - } + } else if (statement.type === 'FunctionDeclaration' || (statement.type === 'FunctionExpression')) { + const closestComment = JavaScriptParser.findCommentBefore(comments, statement.loc.start.line); let returnType = ''; let visibility = '+'; let parameterTypes = []; @@ -158,7 +107,7 @@ class JavaScriptParser { let example = ''; let commentData; if (closestComment >= 0) { - let comment = comments[closestComment].value; + const comment = comments[closestComment].text; commentData = doctrine.parse(comment, { unwrap: true, sloppy: true @@ -190,16 +139,11 @@ class JavaScriptParser { this.functions.push(func); } } else if (statement.type === 'ClassDeclaration') { - let closestComment; - if (!engineMode) { - closestComment = JavaScriptParser.findCommentBefore(comments, statement.loc.start.line); - } else { - closestComment = JavaScriptParser.searchForComment(statement.start, statement.end, previousEnd, comments); - } + const closestComment = JavaScriptParser.findCommentBefore(comments, statement.loc.start.line); let privateClass = false; let d; if (closestComment >= 0) { - let comment = comments[closestComment].value; + const comment = comments[closestComment].text; d = doctrine.parse(comment, { unwrap: true, sloppy: true @@ -219,18 +163,7 @@ class JavaScriptParser { let thing = statement.body.body[n]; if (thing.type === 'MethodDefinition') { - let closestComment; - if (!engineMode) { - closestComment = JavaScriptParser.findCommentBefore(comments, thing.loc.start.line); - } else { - // previousEnd is the end of the node before the ClassDeclaration - let previousThingEnd = previousEnd; - if (n !== 0) { - // record the end of the previous thing inside the ClassDeclaration - previousThingEnd = statement.body.body[n - 1].end; - } - closestComment = JavaScriptParser.searchForComment(thing.key.start, thing.key.end, previousThingEnd, comments); - } + const closestComment = JavaScriptParser.findCommentBefore(comments, thing.loc.start.line); let returnType = ''; let visibility = '+'; let methodArgs = []; @@ -239,7 +172,7 @@ class JavaScriptParser { let example = ''; let commentData; if (closestComment >= 0) { - let comment = comments[closestComment].value; + const comment = comments[closestComment].text; commentData = doctrine.parse(comment, { unwrap: true, sloppy: true @@ -347,10 +280,10 @@ class JavaScriptParser { let foundIndex = -1; for (let n = 0; n < comments.length; n++) { - let comment = comments[n]; - let endComment = parseInt(comment.loc.end.line); + const comment = comments[n]; + const endComment = comment.column.line; - if ((lineNumber - endComment) === 1) { + if ((lineNumber-endComment) === 1) { foundIndex = n; break; } @@ -359,36 +292,6 @@ class JavaScriptParser { return foundIndex; } - /** - * Find the comments that are above and closest to the start of the range. - * This is used in engineMode and supports locating comments that aren't - * directly before a TP function. It assumes that nodes will be in order - * - * @param {integer} rangeStart - the start of the range - * @param {integer} rangeEnd - the end of the range - * @param {integer} stopPoint - the point to stop searching for previous comments - * @param {string[]} comments - the end of the range - * @return {integer} the comment index or -1 if there are no comments - * @private - */ - static searchForComment(rangeStart, rangeEnd, stopPoint, comments) { - let foundIndex = -1; - let distance = -1; - - for (let n = 0; n < comments.length; n++) { - let comment = comments[n]; - let endComment = comment.end; - if (rangeStart > endComment && comment.start > stopPoint) { - - if (distance === -1 || rangeStart - endComment < distance) { - distance = rangeStart - endComment; - foundIndex = n; - } - } - } - return foundIndex; - } - /** * Grabs all the @ prefixed decorators from a comment block. * @param {string} comment - the comment block diff --git a/packages/concerto-core/scripts/parsejs.js b/packages/concerto-core/scripts/parsejs.js index 433e9f24a9..52ae177ae4 100644 --- a/packages/concerto-core/scripts/parsejs.js +++ b/packages/concerto-core/scripts/parsejs.js @@ -34,8 +34,8 @@ function processFile(file, fileProcessor) { let filePath = path.parse(file); if (filePath.ext === '.js' && filePath.base !== 'parser.js') { //ignore the generated parsers let fileContents = fs.readFileSync(file, 'utf8'); - // Specify ES2017 (ES8) as that has async/await, which we use in our APIs. - const parser = new JavaScriptParser(fileContents, program.private, 8, false); + // Specify ES2022 (ES13) as that has static class members, which we use in our APIs. + const parser = new JavaScriptParser(fileContents, program.private, 2022); fileProcessor.generate(program, file, parser.getIncludes(), parser.getClasses(), parser.getFunctions()); } } @@ -73,7 +73,7 @@ function processDirectory(path, fileProcessor) { * --inputDir */ program - .version('0.0.1') + .version('1.0.0') .description('Parses Javascript source and generates output from class and method definitions') .usage('[options]') .option('-o, --outputDir ', 'Output directory') diff --git a/packages/concerto-core/test/scripts/javascriptparser.js b/packages/concerto-core/test/scripts/javascriptparser.js index 987fa9e734..9e14927e53 100644 --- a/packages/concerto-core/test/scripts/javascriptparser.js +++ b/packages/concerto-core/test/scripts/javascriptparser.js @@ -18,7 +18,6 @@ const JavascriptParser = require('../../scripts/javascriptparser'); const fs = require('fs'); const path = require('path'); const doctrine = require('doctrine'); -const acorn = require('acorn'); const chai = require('chai'); chai.should(); chai.use(require('chai-as-promised')); @@ -52,7 +51,7 @@ describe('JavascriptParser', () => { afterEach(() => { sandbox.restore(); }); - it('should use a default ECMAScript version of 7', () => { + it('should use a default ECMAScript version of 2022', () => { const contents = ` let num = 3 ** 2; num **= 2; @@ -76,12 +75,11 @@ describe('JavascriptParser', () => { it('should accept a non-default ECMAScript version of 5', () => { const contents = ` + function inc(arg) { + return arg++; + } `; - - sandbox.stub(acorn.Parser.prototype,'startNode').returns({body:[]}); - sandbox.stub(acorn.Parser.prototype,'finishNode').returns({body:[]}); new JavascriptParser(contents, false, 5); - }); it('should accept a non-default ECMAScript version of 5', () => { @@ -263,28 +261,6 @@ describe('JavascriptParser', () => { }); }); - describe('#getTokens', () => { - afterEach(() => { - delete global.composerJavaScriptParserNoTokens; - }); - - it('should return all of the tokens', () => { - const contents = 'eval(true)'; - const parser = new JavascriptParser(contents); - const tokens = parser.getTokens(); - tokens.should.have.lengthOf(5); - tokens.should.all.have.property('loc'); - }); - - it('should return no tokens if token collection is disabled', () => { - global.composerJavaScriptParserNoTokens = true; - const contents = 'eval(true)'; - const parser = new JavascriptParser(contents); - const tokens = parser.getTokens(); - tokens.should.have.lengthOf(0); - }); - }); - describe('#getText', () => { it('should use the substring method correctly', () => { JavascriptParser.getText(0, 6, 'strings are cool').should.equal('string'); @@ -299,91 +275,6 @@ describe('JavascriptParser', () => { }); }); - describe('#searchForComment', () => { - let commentSpy; - beforeEach(() => { - commentSpy = sandbox.spy(JavascriptParser, 'searchForComment'); - }); - - it('should handle comments not directly before function', () => { - const code = readTestExample('CommentNotDirectlyBeforeFunction.js.txt'); - sinon.assert.notCalled(commentSpy); - const parser = new JavascriptParser(code); - parser.getFunctions().length.should.equal(1); - const func = parser.getFunctions()[0]; - func.decorators.should.deep.equal(['param', 'transaction']); - func.parameterTypes.length.should.equal(1); - func.parameterTypes[0].should.equal('org.acme.mynetwork.Trade'); - func.name.should.equal('tradeCommodity'); - sinon.assert.called(commentSpy); - }); - - it('should handle the basic of examples', () => { - const code = readTestExample('BasicExample.js.txt'); - sinon.assert.notCalled(commentSpy); - const parser = new JavascriptParser(code); - parser.getFunctions().length.should.equal(1); - const func = parser.getFunctions()[0]; - func.decorators.should.deep.equal(['param', 'transaction']); - func.parameterTypes.length.should.equal(1); - func.parameterTypes[0].should.equal('org.acme.mynetwork.Trade'); - func.name.should.equal('tradeCommodity'); - sinon.assert.called(commentSpy); - }); - - it('should handle the uncommented function following commented function', () => { - const code = readTestExample('UncommentedFollowingCommented.js.txt'); - sinon.assert.notCalled(commentSpy); - const parser = new JavascriptParser(code); - parser.getFunctions().length.should.equal(2); - const func = parser.getFunctions()[0]; - func.decorators.should.deep.equal(['param', 'transaction']); - func.name.should.equal('tradeCommodity'); - func.parameterTypes.length.should.equal(1); - func.parameterTypes[0].should.equal('org.acme.mynetwork.Trade'); - const func2 = parser.getFunctions()[1]; - func2.decorators.length.should.equal(0); - func2.parameterTypes.length.should.equal(0); - sinon.assert.called(commentSpy); - }); - - it('should handle the class methods', () => { - const code = readTestExample('ClassExample.js.txt'); - sinon.assert.notCalled(commentSpy); - const parser = new JavascriptParser(code, false, 7, true); - const clazz = parser.getClasses(); - clazz.length.should.equal(1); - const methods = clazz[0].methods; - methods.length.should.equal(3); - methods[0].decorators.length.should.equal(0); - methods[1].decorators.should.deep.equal(['param', 'transaction']); - methods[2].decorators.length.should.equal(0); - sinon.assert.called(commentSpy); - }); - - it('should handle the a complex example', () => { - const code = readTestExample('ComplexExample.js.txt'); - sinon.assert.notCalled(commentSpy); - const parser = new JavascriptParser(code); - const funcs = parser.getFunctions(); - funcs.length.should.equal(12); - const noDecorators = [0, 1, 2, 3, 5, 6, 9, 10]; - const allDecorators = [7, 8, 11]; - noDecorators.forEach((value) => { - funcs[value].decorators.length.should.equal(0); - }); - allDecorators.forEach((value) => { - funcs[value].decorators.length.should.equal(2); - funcs[value].decorators.should.deep.equal(['param', 'transaction']); - }); - funcs[4].decorators.length.should.equal(1); - funcs[4].decorators[0].should.equal('transaction'); - sinon.assert.called(commentSpy); - }); - - }); - - describe('#findCommentBefore', () => { let commentSpy; beforeEach(() => { diff --git a/packages/concerto-core/types/index.d.ts b/packages/concerto-core/types/index.d.ts index eab3b18faf..3d3c88b02c 100644 --- a/packages/concerto-core/types/index.d.ts +++ b/packages/concerto-core/types/index.d.ts @@ -230,11 +230,8 @@ declare module '@accordproject/concerto-core' { // Globalize export function Globalize(locale: string): any; - - export namespace Globalize { - function messageFormatter(message: string): any; - function formatMessage(message: string): any; - } + function messageFormatter(message: string): any; + function formatMessage(message: string): any; // Introspector export class Introspector { @@ -418,9 +415,7 @@ declare module '@accordproject/concerto-core' { utcOffset: number } - export namespace DateTimeUtil { - function setCurrentTime(currentTime?: string, utcOffset?: number): CurrentTime; - } + function setCurrentTime(currentTime?: string, utcOffset?: number): CurrentTime; // TypedStack export class TypedStack { @@ -440,7 +435,7 @@ declare module '@accordproject/concerto-core' { getTypeDeclaration(obj: any): ClassDeclaration; getIdentifier(obj: any): string; isIdentifiable(obj: any): boolean; - isRelationship(obj: aby): boolean; + isRelationship(obj: any): boolean; setIdentifier(obj: any, id: string): any; getFullyQualifiedIdentifier(obj: any): string; toURI(obj: any): string; @@ -450,12 +445,12 @@ declare module '@accordproject/concerto-core' { } // MetaModel - export namespace MetaModel { - const metaModelCto: string; - function modelFileToMetaModel(modelFile: ModelFile, validate?: boolean): any; - function ctoToMetaModel(model: string, validate?: boolean): any; - function ctoToMetaModelAndResolve(modelManager: ModelManager, model: string, validate?: boolean); - function ctoFromMetaModel(metaModel: any, validate?: boolean): string; + export class MetaModel { + static metaModelCto: string; + static modelFileToMetaModel(modelFile: ModelFile, validate?: boolean): any; + static ctoToMetaModel(model: string, validate?: boolean): any; + static ctoToMetaModelAndResolve(modelManager: ModelManager, model: string, validate?: boolean) : any; + static ctoFromMetaModel(metaModel: any, validate?: boolean): string; } // version diff --git a/packages/concerto-tools/package.json b/packages/concerto-tools/package.json index 030053b10e..94d5f21132 100644 --- a/packages/concerto-tools/package.json +++ b/packages/concerto-tools/package.json @@ -38,7 +38,7 @@ "chai": "4.3.4", "chai-as-promised": "7.1.1", "chai-things": "0.2.0", - "eslint": "7.24.0", + "eslint": "8.2.0", "jsdoc": "^3.6.7", "license-check-and-add": "2.3.6", "mocha": "8.3.2", diff --git a/packages/concerto-tools/types/index.d.ts b/packages/concerto-tools/types/index.d.ts index df9a4fc00e..a8af891c79 100644 --- a/packages/concerto-tools/types/index.d.ts +++ b/packages/concerto-tools/types/index.d.ts @@ -1,95 +1,93 @@ import { AssetDeclaration, ClassDeclaration, ConceptDeclaration, EnumDeclaration, EnumValueDeclaration, ModelManager, ModelFile, Field, Relationship, RelationshipDeclaration, TransactionDeclaration } from '@accordproject/concerto'; declare module '@accordproject/concerto-tools' { - export namespace CodeGen { - export abstract class AbstractPlugin { - addClassImports(clazz: ClassDeclaration, parameters: any, options: any): void; - addClassAnnotations(clazz: ClassDeclaration, parameters: any, options: any): void; - addClassMethods(clazz: ClassDeclaration, parameters: any, options: any): void; - addEnumAnnotations(enumDecl: EnumDeclaration, parameters: any, options: any): void; - } - - export class GoLangVisitor { - visit(thing: any, parameters: any): any | null; - visitModelManager(modelManager: ModelManager, parameters: any): any | null; - visitModelFile(modelFile: ModelFile, parameters: any): any | null; - visitEnumDeclaration(enumDeclaration: EnumDeclaration, parameters: any): any | null; - visitClassDeclaration(classDeclaration: ClassDeclaration, parameters: any): any | null; - visitField(field: Field, parameters: any): any | null; - visitEnumValueDeclaration(enumValueDeclaration: EnumValueDeclaration, parameters: any): any | null; - visitRelationship(relationship: Relationship, parameters: any): any | null; - containsDateTimeField(modelFile: ModelFile): boolean; - toGoType(type: string): string; - toGoPackageName(namespace: string): string; - } - - export class JSONSchemaVisitor { - visit(thing: any, parameters: any): any | null; - visitModelManager(modelManager: ModelManager, parameters: any): any | null; - visitModelFile(modelFile: ModelFile, parameters: any): any | null; - visitAssetDeclaration(assetDeclaration: AssetDeclaration, parameters: any): any | null; - visitTransactionDeclaration(transactionDeclaration: TransactionDeclaration, parameters: any): any | null; - visitConceptDeclaration(conceptDeclaration: ConceptDeclaration, parameters: any): any | null; - visitClassDeclaration(classDeclaration: ClassDeclaration, parameters: any): any | null; - visitClassDeclarationCommon(classDeclaration: ClassDeclaration, parameters: any, jsonSchema: any): any | null; - visitField(field: Field, parameters: any): any | null; - visitEnumValueDeclaration(enumValueDeclaration: EnumValueDeclaration, parameters: any): any | null; - visitRelationshipDeclaration(relationshipDeclaration: RelationshipDeclaration, parameters: any): any | null; - } - - export class XmlSchemaVisitor { - visit(thing: any, parameters: any): any | null; - visitModelManager(modelManager: ModelManager, parameters: any): any | null; - visitModelFile(modelFile: ModelFile, parameters: any): any | null; - visitEnumDeclaration(enumDeclaration: EnumDeclaration, parameters: any): any | null; - visitClassDeclaration(classDeclaration: ClassDeclaration, parameters: any): any | null; - visitField(field: Field, parameters: any): any | null; - visitEnumValueDeclaration(enumValueDeclaration: EnumValueDeclaration, parameters: any): any | null; - visitRelationship(relationship: Relationship, parameters: any): any | null; - toXsType(type: string): string; - } - - export class PlantUMLVisitor { - visit(thing: any, parameters: any): any | null; - visitModelManager(modelManager: ModelManager, parameters: any): any | null; - visitModelFile(modelFile: ModelFile, parameters: any): any | null; - visitAssetDeclaration(assetDeclaration: AssetDeclaration, parameters: any): any | null; - visitEnumDeclaration(enumDeclaration: EnumDeclaration, parameters: any): any | null; - visitParticipantDeclaration(classDeclaration: ClassDeclaration, parameters: any): any | null; - visitTransactionDeclaration(transactionDeclaration: TransactionDeclaration, parameters: any): any | null; - visitClassDeclaration(classDeclaration: ClassDeclaration, parameters: any): any | null; - visitField(field: Field, parameters: any): any | null; - visitEnumValueDeclaration(enumValueDeclaration: EnumValueDeclaration, parameters: any): any | null; - visitRelationship(relationship: Relationship, parameters: any): any | null; - } - - export class TypescriptVisitor { - visit(thing: any, parameters: any): any | null; - visitModelManager(modelManager: ModelManager, parameters: any): any | null; - visitModelFile(modelFile: ModelFile, parameters: any): any | null; - visitEnumDeclaration(enumDeclaration: EnumDeclaration, parameters: any): any | null; - visitClassDeclaration(classDeclaration: ClassDeclaration, parameters: any): any | null; - visitField(field: Field, parameters: any): any | null; - visitEnumValueDeclaration(enumValueDeclaration: EnumValueDeclaration, parameters: any): any | null; - visitRelationship(relationship: Relationship, parameters: any): any | null; - toTsType(type: string): string; - } - - export class JavaVisitor { - visit(thing: any, parameters: any): any | null; - visitModelManager(modelManager: ModelManager, parameters: any): any | null; - visitModelFile(modelFile: ModelFile, parameters: any): any | null; - startClassFile(classDeclaration: ClassDeclaration, parameters: any): any | null; - endClassFile(classDeclaration: ClassDeclaration, parameters: any): any | null; - visitEnumDeclaration(enumDeclaration: EnumDeclaration, parameters: any): any | null; - visitClassDeclaration(classDeclaration: ClassDeclaration, parameters: any): any | null; - visitField(field: Field, parameters: any): any | null; - visitEnumValueDeclaration(enumValueDeclaration: EnumValueDeclaration, parameters: any): any | null; - visitRelationship(relationship: Relationship, parameters: any): any | null; - toJavaType(type: string): string; - capitalizeFirstLetter(s: string): string; - } + export abstract class AbstractPlugin { + addClassImports(clazz: ClassDeclaration, parameters: any, options: any): void; + addClassAnnotations(clazz: ClassDeclaration, parameters: any, options: any): void; + addClassMethods(clazz: ClassDeclaration, parameters: any, options: any): void; + addEnumAnnotations(enumDecl: EnumDeclaration, parameters: any, options: any): void; } - + + export class GoLangVisitor { + visit(thing: any, parameters: any): any | null; + visitModelManager(modelManager: ModelManager, parameters: any): any | null; + visitModelFile(modelFile: ModelFile, parameters: any): any | null; + visitEnumDeclaration(enumDeclaration: EnumDeclaration, parameters: any): any | null; + visitClassDeclaration(classDeclaration: ClassDeclaration, parameters: any): any | null; + visitField(field: Field, parameters: any): any | null; + visitEnumValueDeclaration(enumValueDeclaration: EnumValueDeclaration, parameters: any): any | null; + visitRelationship(relationship: Relationship, parameters: any): any | null; + containsDateTimeField(modelFile: ModelFile): boolean; + toGoType(type: string): string; + toGoPackageName(namespace: string): string; + } + + export class JSONSchemaVisitor { + visit(thing: any, parameters: any): any | null; + visitModelManager(modelManager: ModelManager, parameters: any): any | null; + visitModelFile(modelFile: ModelFile, parameters: any): any | null; + visitAssetDeclaration(assetDeclaration: AssetDeclaration, parameters: any): any | null; + visitTransactionDeclaration(transactionDeclaration: TransactionDeclaration, parameters: any): any | null; + visitConceptDeclaration(conceptDeclaration: ConceptDeclaration, parameters: any): any | null; + visitClassDeclaration(classDeclaration: ClassDeclaration, parameters: any): any | null; + visitClassDeclarationCommon(classDeclaration: ClassDeclaration, parameters: any, jsonSchema: any): any | null; + visitField(field: Field, parameters: any): any | null; + visitEnumValueDeclaration(enumValueDeclaration: EnumValueDeclaration, parameters: any): any | null; + visitRelationshipDeclaration(relationshipDeclaration: RelationshipDeclaration, parameters: any): any | null; + } + + export class XmlSchemaVisitor { + visit(thing: any, parameters: any): any | null; + visitModelManager(modelManager: ModelManager, parameters: any): any | null; + visitModelFile(modelFile: ModelFile, parameters: any): any | null; + visitEnumDeclaration(enumDeclaration: EnumDeclaration, parameters: any): any | null; + visitClassDeclaration(classDeclaration: ClassDeclaration, parameters: any): any | null; + visitField(field: Field, parameters: any): any | null; + visitEnumValueDeclaration(enumValueDeclaration: EnumValueDeclaration, parameters: any): any | null; + visitRelationship(relationship: Relationship, parameters: any): any | null; + toXsType(type: string): string; + } + + export class PlantUMLVisitor { + visit(thing: any, parameters: any): any | null; + visitModelManager(modelManager: ModelManager, parameters: any): any | null; + visitModelFile(modelFile: ModelFile, parameters: any): any | null; + visitAssetDeclaration(assetDeclaration: AssetDeclaration, parameters: any): any | null; + visitEnumDeclaration(enumDeclaration: EnumDeclaration, parameters: any): any | null; + visitParticipantDeclaration(classDeclaration: ClassDeclaration, parameters: any): any | null; + visitTransactionDeclaration(transactionDeclaration: TransactionDeclaration, parameters: any): any | null; + visitClassDeclaration(classDeclaration: ClassDeclaration, parameters: any): any | null; + visitField(field: Field, parameters: any): any | null; + visitEnumValueDeclaration(enumValueDeclaration: EnumValueDeclaration, parameters: any): any | null; + visitRelationship(relationship: Relationship, parameters: any): any | null; + } + + export class TypescriptVisitor { + visit(thing: any, parameters: any): any | null; + visitModelManager(modelManager: ModelManager, parameters: any): any | null; + visitModelFile(modelFile: ModelFile, parameters: any): any | null; + visitEnumDeclaration(enumDeclaration: EnumDeclaration, parameters: any): any | null; + visitClassDeclaration(classDeclaration: ClassDeclaration, parameters: any): any | null; + visitField(field: Field, parameters: any): any | null; + visitEnumValueDeclaration(enumValueDeclaration: EnumValueDeclaration, parameters: any): any | null; + visitRelationship(relationship: Relationship, parameters: any): any | null; + toTsType(type: string): string; + } + + export class JavaVisitor { + visit(thing: any, parameters: any): any | null; + visitModelManager(modelManager: ModelManager, parameters: any): any | null; + visitModelFile(modelFile: ModelFile, parameters: any): any | null; + startClassFile(classDeclaration: ClassDeclaration, parameters: any): any | null; + endClassFile(classDeclaration: ClassDeclaration, parameters: any): any | null; + visitEnumDeclaration(enumDeclaration: EnumDeclaration, parameters: any): any | null; + visitClassDeclaration(classDeclaration: ClassDeclaration, parameters: any): any | null; + visitField(field: Field, parameters: any): any | null; + visitEnumValueDeclaration(enumValueDeclaration: EnumValueDeclaration, parameters: any): any | null; + visitRelationship(relationship: Relationship, parameters: any): any | null; + toJavaType(type: string): string; + capitalizeFirstLetter(s: string): string; + } + export const version: any; }