diff --git a/abap-api-tools/.gitignore b/abap-api-tools/.gitignore index 14cc414e..425a357d 100644 --- a/abap-api-tools/.gitignore +++ b/abap-api-tools/.gitignore @@ -8,7 +8,7 @@ node_modules dist api config -test +ci # editors .idea diff --git a/abap-api-tools/README.md b/abap-api-tools/README.md index 8e2c3d6a..37c2beed 100644 --- a/abap-api-tools/README.md +++ b/abap-api-tools/README.md @@ -22,6 +22,7 @@ Command line tool for pattern based applications with ABAP/HANA systems. - [ui elements](#ui-elements) - [Custom ui configurations](#custom-ui-configurations) - [i18n](#i18n) +- [CLI API](#cli-api) - [Known Issues](#known-issues) - [Getting Support](#getting-support) - [Contributing](#contributing) @@ -363,6 +364,38 @@ short: SCRTEXT_S: Postl Code ``` +## CLI API + +Your tools and applications can use CLI API `call` and `get` methods, to access ABAP annotations and call templates. + +Either the destination id or connection parameters can be provided, together with one single RFM name or array of RFM names. + +Check [unit tests](https://github.com/SAP/fundamental-tools/tree/main/abap-api-tools/tests) for data structures. + +```ts +import { CliApi, CliResult, RfcConnectionParameters } from "abap-api-tools"; + +const cp: RfcConnectionParameters = { + user: "demo", + passwd: "welcome", + ashost: "11.12.13.14", + sysnr: "01", + client: "321", + lang: "de", +}; + +(async () => { + let R:CliResult; + + const api = new CliApi(); + + R = await a.get(cp, ["stfc_connection", "stfc_structure"]); // annotations only + + R = await a.call("MME", "stfc_connection"); // annotations and call templates + +})(); +``` + ## Known Issues Click [here](https://github.com/SAP/fundamental-tools/issues) to view the current issues. diff --git a/abap-api-tools/package-lock.json b/abap-api-tools/package-lock.json index 8d243549..95322a45 100644 --- a/abap-api-tools/package-lock.json +++ b/abap-api-tools/package-lock.json @@ -1,11 +1,11 @@ { "name": "abap-api-tools", - "version": "1.6.4", + "version": "1.7.0", "lockfileVersion": 2, "requires": true, "packages": { "": { - "version": "1.6.4", + "version": "1.7.0", "cpu": [ "!arm" ], @@ -37,25 +37,25 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", "dev": true, "dependencies": { - "@babel/highlight": "^7.12.13" + "@babel/highlight": "^7.10.4" } }, "node_modules/@babel/core": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.13.tgz", - "integrity": "sha512-BQKE9kXkPlXHPeqissfxo0lySWJcYdEP0hdtJOH/iJfDdhOCcgtNCjftCJg3qqauB4h+lz2N6ixM++b9DN1Tcw==", + "version": "7.12.16", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.16.tgz", + "integrity": "sha512-t/hHIB504wWceOeaOoONOhu+gX+hpjfeN6YRBT209X/4sibZQfSF1I0HFRRlBe97UZZosGx5XwUg1ZgNbelmNw==", "dev": true, "dependencies": { "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.12.13", + "@babel/generator": "^7.12.15", "@babel/helper-module-transforms": "^7.12.13", "@babel/helpers": "^7.12.13", - "@babel/parser": "^7.12.13", + "@babel/parser": "^7.12.16", "@babel/template": "^7.12.13", "@babel/traverse": "^7.12.13", "@babel/types": "^7.12.13", @@ -75,6 +75,15 @@ "url": "https://opencollective.com/babel" } }, + "node_modules/@babel/core/node_modules/@babel/code-frame": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", + "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.12.13" + } + }, "node_modules/@babel/core/node_modules/semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -134,9 +143,9 @@ } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.13.tgz", - "integrity": "sha512-B+7nN0gIL8FZ8SvMcF+EPyB21KnCcZHQZFczCxbiNGV/O0rsrSBlWGLzmtBJ3GMjSVMIm4lpFhR+VdVBuIsUcQ==", + "version": "7.12.16", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.16.tgz", + "integrity": "sha512-zYoZC1uvebBFmj1wFAlXwt35JLEgecefATtKp20xalwEK8vHAixLBXTGxNrVGEmTT+gzOThUgr8UEdgtalc1BQ==", "dev": true, "dependencies": { "@babel/types": "^7.12.13" @@ -313,9 +322,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.12.15", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.15.tgz", - "integrity": "sha512-AQBOU2Z9kWwSZMd6lNjCX0GUgFonL1wAM1db8L8PMk9UDaGsRCArBkU4Sc+UCM3AE4hjbXx+h58Lb3QT4oRmrA==", + "version": "7.12.16", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.16.tgz", + "integrity": "sha512-c/+u9cqV6F0+4Hpq01jnJO+GLp2DdT63ppz9Xa+6cHaajM9VFzK/iDXiKK65YtpeVwu+ctfS6iqlMqRgQRzeCw==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -479,6 +488,15 @@ "@babel/types": "^7.12.13" } }, + "node_modules/@babel/template/node_modules/@babel/code-frame": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", + "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.12.13" + } + }, "node_modules/@babel/traverse": { "version": "7.12.13", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.13.tgz", @@ -496,6 +514,15 @@ "lodash": "^4.17.19" } }, + "node_modules/@babel/traverse/node_modules/@babel/code-frame": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", + "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.12.13" + } + }, "node_modules/@babel/traverse/node_modules/globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -641,9 +668,9 @@ "dev": true }, "node_modules/@istanbuljs/schema": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", - "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==", + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true, "engines": { "node": ">=8" @@ -981,9 +1008,9 @@ } }, "node_modules/@types/graceful-fs": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.4.tgz", - "integrity": "sha512-mWA/4zFQhfvOA8zWkXobwJvBD7vzcxgrOQ0J5CH1votGqdq9m7+FwtGaqyCZqC3NyyBkc9z4m+iry4LlqcMWJg==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", + "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", "dev": true, "dependencies": { "@types/node": "*" @@ -1026,9 +1053,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "14.14.25", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.25.tgz", - "integrity": "sha512-EPpXLOVqDvisVxtlbvzfyqSsFeQxltFbluZNRndIb8tr9KiBnYNLzrc1N3pyKUCww2RNrfHDViqDWWE1LCJQtQ==", + "version": "14.14.28", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.28.tgz", + "integrity": "sha512-lg55ArB+ZiHHbBBttLpzD07akz0QPrZgUODNakeC09i62dnrywr9mFErHuaPlB6I7z+sEbK+IYmplahvplCj2g==", "dev": true }, "node_modules/@types/normalize-package-data": { @@ -1038,9 +1065,9 @@ "dev": true }, "node_modules/@types/prettier": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.2.0.tgz", - "integrity": "sha512-O3SQC6+6AySHwrspYn2UvC6tjo6jCTMMmylxZUFhE1CulVu5l3AxU6ca9lrJDTQDVllF62LIxVSx5fuYL6LiZg==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.2.1.tgz", + "integrity": "sha512-DxZZbyMAM9GWEzXL+BMZROWz9oo6A9EilwwOMET2UVu2uZTqMWS5S69KVtuVKaRjCUpcrOXRalet86/OpG4kqw==", "dev": true }, "node_modules/@types/sprintf-js": { @@ -1071,13 +1098,13 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "4.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.15.0.tgz", - "integrity": "sha512-DJgdGZW+8CFUTz5C/dnn4ONcUm2h2T0itWD85Ob5/V27Ndie8hUoX5HKyGssvR8sUMkAIlUc/AMK67Lqa3kBIQ==", + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.15.1.tgz", + "integrity": "sha512-yW2epMYZSpNJXZy22Biu+fLdTG8Mn6b22kR3TqblVk50HGNV8Zya15WAXuQCr8tKw4Qf1BL4QtI6kv6PCkLoJw==", "dev": true, "dependencies": { - "@typescript-eslint/experimental-utils": "4.15.0", - "@typescript-eslint/scope-manager": "4.15.0", + "@typescript-eslint/experimental-utils": "4.15.1", + "@typescript-eslint/scope-manager": "4.15.1", "debug": "^4.1.1", "functional-red-black-tree": "^1.0.1", "lodash": "^4.17.15", @@ -1103,15 +1130,15 @@ } }, "node_modules/@typescript-eslint/experimental-utils": { - "version": "4.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.15.0.tgz", - "integrity": "sha512-V4vaDWvxA2zgesg4KPgEGiomWEBpJXvY4ZX34Y3qxK8LUm5I87L+qGIOTd9tHZOARXNRt9pLbblSKiYBlGMawg==", + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.15.1.tgz", + "integrity": "sha512-9LQRmOzBRI1iOdJorr4jEnQhadxK4c9R2aEAsm7WE/7dq8wkKD1suaV0S/JucTL8QlYUPU1y2yjqg+aGC0IQBQ==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.3", - "@typescript-eslint/scope-manager": "4.15.0", - "@typescript-eslint/types": "4.15.0", - "@typescript-eslint/typescript-estree": "4.15.0", + "@typescript-eslint/scope-manager": "4.15.1", + "@typescript-eslint/types": "4.15.1", + "@typescript-eslint/typescript-estree": "4.15.1", "eslint-scope": "^5.0.0", "eslint-utils": "^2.0.0" }, @@ -1127,14 +1154,14 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "4.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.15.0.tgz", - "integrity": "sha512-L6Dtbq8Bc7g2aZwnIBETpmUa9XDKCMzKVwAArnGp5Mn7PRNFjf3mUzq8UeBjL3K8t311hvevnyqXAMSmxO8Gpg==", + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.15.1.tgz", + "integrity": "sha512-V8eXYxNJ9QmXi5ETDguB7O9diAXlIyS+e3xzLoP/oVE4WCAjssxLIa0mqCLsCGXulYJUfT+GV70Jv1vHsdKwtA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "4.15.0", - "@typescript-eslint/types": "4.15.0", - "@typescript-eslint/typescript-estree": "4.15.0", + "@typescript-eslint/scope-manager": "4.15.1", + "@typescript-eslint/types": "4.15.1", + "@typescript-eslint/typescript-estree": "4.15.1", "debug": "^4.1.1" }, "engines": { @@ -1154,13 +1181,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "4.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.15.0.tgz", - "integrity": "sha512-CSNBZnCC2jEA/a+pR9Ljh8Y+5TY5qgbPz7ICEk9WCpSEgT6Pi7H2RIjxfrrbUXvotd6ta+i27sssKEH8Azm75g==", + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.15.1.tgz", + "integrity": "sha512-ibQrTFcAm7yG4C1iwpIYK7vDnFg+fKaZVfvyOm3sNsGAerKfwPVFtYft5EbjzByDJ4dj1WD8/34REJfw/9wdVA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "4.15.0", - "@typescript-eslint/visitor-keys": "4.15.0" + "@typescript-eslint/types": "4.15.1", + "@typescript-eslint/visitor-keys": "4.15.1" }, "engines": { "node": "^8.10.0 || ^10.13.0 || >=11.10.1" @@ -1171,9 +1198,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "4.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.15.0.tgz", - "integrity": "sha512-su4RHkJhS+iFwyqyXHcS8EGPlUVoC+XREfy5daivjLur9JP8GhvTmDipuRpcujtGC4M+GYhUOJCPDE3rC5NJrg==", + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.15.1.tgz", + "integrity": "sha512-iGsaUyWFyLz0mHfXhX4zO6P7O3sExQpBJ2dgXB0G5g/8PRVfBBsmQIc3r83ranEQTALLR3Vko/fnCIVqmH+mPw==", "dev": true, "engines": { "node": "^8.10.0 || ^10.13.0 || >=11.10.1" @@ -1184,13 +1211,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "4.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.15.0.tgz", - "integrity": "sha512-jG6xTmcNbi6xzZq0SdWh7wQ9cMb2pqXaUp6bUZOMsIlu5aOlxGxgE/t6L/gPybybQGvdguajXGkZKSndZJpksA==", + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.15.1.tgz", + "integrity": "sha512-z8MN3CicTEumrWAEB2e2CcoZa3KP9+SMYLIA2aM49XW3cWIaiVSOAGq30ffR5XHxRirqE90fgLw3e6WmNx5uNw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "4.15.0", - "@typescript-eslint/visitor-keys": "4.15.0", + "@typescript-eslint/types": "4.15.1", + "@typescript-eslint/visitor-keys": "4.15.1", "debug": "^4.1.1", "globby": "^11.0.1", "is-glob": "^4.0.1", @@ -1211,12 +1238,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "4.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.15.0.tgz", - "integrity": "sha512-RnDtJwOwFucWFAMjG3ghCG/ikImFJFEg20DI7mn4pHEx3vC48lIAoyjhffvfHmErRDboUPC7p9Z2il4CLb7qxA==", + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.15.1.tgz", + "integrity": "sha512-tYzaTP9plooRJY8eNlpAewTOqtWW/4ff/5wBjNVaJ0S0wC4Gpq/zDVRTJa5bq2v1pCNQ08xxMCndcvR+h7lMww==", "dev": true, "dependencies": { - "@typescript-eslint/types": "4.15.0", + "@typescript-eslint/types": "4.15.1", "eslint-visitor-keys": "^2.0.0" }, "engines": { @@ -2311,12 +2338,12 @@ } }, "node_modules/eslint": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.19.0.tgz", - "integrity": "sha512-CGlMgJY56JZ9ZSYhJuhow61lMPPjUzWmChFya71Z/jilVos7mR/jPgaEfVGgMBY5DshbKdG8Ezb8FDCHcoMEMg==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.20.0.tgz", + "integrity": "sha512-qGi0CTcOGP2OtCQBgWZlQjcTuP0XkIpYFj25XtRTQSHC+umNnp7UMshr2G8SLsRFYDdAPFeHOsiteadmMH02Yw==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.0.0", + "@babel/code-frame": "7.12.11", "@eslint/eslintrc": "^0.3.0", "ajv": "^6.10.0", "chalk": "^4.0.0", @@ -2328,7 +2355,7 @@ "eslint-utils": "^2.1.0", "eslint-visitor-keys": "^2.0.0", "espree": "^7.3.1", - "esquery": "^1.2.0", + "esquery": "^1.4.0", "esutils": "^2.0.2", "file-entry-cache": "^6.0.0", "functional-red-black-tree": "^1.0.1", @@ -3127,9 +3154,9 @@ } }, "node_modules/graceful-fs": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.5.tgz", - "integrity": "sha512-kBBSQbz2K0Nyn+31j/w36fUfxkBW9/gfwRWdUY1ULReH3iokVJgddZAFcD1D0xlgTmFxJCbUkUclAlc6/IDJkw==", + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", "dev": true }, "node_modules/growly": { @@ -5325,6 +5352,26 @@ "node": ">=0.6" } }, + "node_modules/queue-microtask": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.2.tgz", + "integrity": "sha512-dB15eXv3p2jDlbOiNLyMabYg1/sXvppd8DP2J3EOCQ0AkuSXCW2tP7mnVouVLJKgUMY6yP0kcQDVpLCN13h4Xg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/react-is": { "version": "17.0.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.1.tgz", @@ -5545,12 +5592,12 @@ "dev": true }, "node_modules/resolve": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", - "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", "dev": true, "dependencies": { - "is-core-module": "^2.1.0", + "is-core-module": "^2.2.0", "path-parse": "^1.0.6" }, "funding": { @@ -5638,9 +5685,9 @@ } }, "node_modules/run-parallel": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.10.tgz", - "integrity": "sha512-zb/1OuZ6flOlH6tQyMPUrE3x3Ulxjlo9WIVXR4yVYi4H9UXQaeIsPbLn2R3O3vQCnDKkAl2qHiuocKKX4Tz/Sw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "dev": true, "funding": [ { @@ -5655,7 +5702,10 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } }, "node_modules/safe-buffer": { "version": "5.1.2", @@ -6654,9 +6704,9 @@ } }, "node_modules/table/node_modules/ajv": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.0.4.tgz", - "integrity": "sha512-xzzzaqgEQfmuhbhAoqjJ8T/1okb6gAzXn/eQRNpAN1AEUoHJTNF9xCDRTtf/s3SKldtZfa+RJeTs+BQq+eZ/sw==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.1.1.tgz", + "integrity": "sha512-ga/aqDYnUy/o7vbsRTFhhTsNeXiYb5JWDIcRIeZfwRNCefwjNTVYCGdGSUrEmiu3yDK3vFvNbgJxvrQW4JXrYQ==", "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", @@ -6888,9 +6938,9 @@ } }, "node_modules/typescript": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz", - "integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.5.tgz", + "integrity": "sha512-6OSu9PTIzmn9TCDiovULTnET6BgXtDYL4Gg4szY+cGsc3JP1dQL8qvE8kShTRx1NIw4Q9IBHlwODjkjWEtMUyA==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -7257,9 +7307,9 @@ } }, "node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "version": "20.2.5", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.5.tgz", + "integrity": "sha512-jYRGS3zWy20NtDtK2kBgo/TlAoy5YUuhD9/LZ7z7W4j1Fdw2cqD0xEEclf8fxc8xjD6X5Qr+qQQwCEsP8iRiYg==", "engines": { "node": ">=10" } @@ -7267,25 +7317,25 @@ }, "dependencies": { "@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", "dev": true, "requires": { - "@babel/highlight": "^7.12.13" + "@babel/highlight": "^7.10.4" } }, "@babel/core": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.13.tgz", - "integrity": "sha512-BQKE9kXkPlXHPeqissfxo0lySWJcYdEP0hdtJOH/iJfDdhOCcgtNCjftCJg3qqauB4h+lz2N6ixM++b9DN1Tcw==", + "version": "7.12.16", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.16.tgz", + "integrity": "sha512-t/hHIB504wWceOeaOoONOhu+gX+hpjfeN6YRBT209X/4sibZQfSF1I0HFRRlBe97UZZosGx5XwUg1ZgNbelmNw==", "dev": true, "requires": { "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.12.13", + "@babel/generator": "^7.12.15", "@babel/helper-module-transforms": "^7.12.13", "@babel/helpers": "^7.12.13", - "@babel/parser": "^7.12.13", + "@babel/parser": "^7.12.16", "@babel/template": "^7.12.13", "@babel/traverse": "^7.12.13", "@babel/types": "^7.12.13", @@ -7298,6 +7348,15 @@ "source-map": "^0.5.0" }, "dependencies": { + "@babel/code-frame": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", + "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.12.13" + } + }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -7352,9 +7411,9 @@ } }, "@babel/helper-member-expression-to-functions": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.13.tgz", - "integrity": "sha512-B+7nN0gIL8FZ8SvMcF+EPyB21KnCcZHQZFczCxbiNGV/O0rsrSBlWGLzmtBJ3GMjSVMIm4lpFhR+VdVBuIsUcQ==", + "version": "7.12.16", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.16.tgz", + "integrity": "sha512-zYoZC1uvebBFmj1wFAlXwt35JLEgecefATtKp20xalwEK8vHAixLBXTGxNrVGEmTT+gzOThUgr8UEdgtalc1BQ==", "dev": true, "requires": { "@babel/types": "^7.12.13" @@ -7518,9 +7577,9 @@ } }, "@babel/parser": { - "version": "7.12.15", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.15.tgz", - "integrity": "sha512-AQBOU2Z9kWwSZMd6lNjCX0GUgFonL1wAM1db8L8PMk9UDaGsRCArBkU4Sc+UCM3AE4hjbXx+h58Lb3QT4oRmrA==", + "version": "7.12.16", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.16.tgz", + "integrity": "sha512-c/+u9cqV6F0+4Hpq01jnJO+GLp2DdT63ppz9Xa+6cHaajM9VFzK/iDXiKK65YtpeVwu+ctfS6iqlMqRgQRzeCw==", "dev": true }, "@babel/plugin-syntax-async-generators": { @@ -7640,6 +7699,17 @@ "@babel/code-frame": "^7.12.13", "@babel/parser": "^7.12.13", "@babel/types": "^7.12.13" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", + "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.12.13" + } + } } }, "@babel/traverse": { @@ -7659,6 +7729,15 @@ "lodash": "^4.17.19" }, "dependencies": { + "@babel/code-frame": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", + "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.12.13" + } + }, "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -7786,9 +7865,9 @@ } }, "@istanbuljs/schema": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", - "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==", + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true }, "@jest/console": { @@ -8080,9 +8159,9 @@ } }, "@types/graceful-fs": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.4.tgz", - "integrity": "sha512-mWA/4zFQhfvOA8zWkXobwJvBD7vzcxgrOQ0J5CH1votGqdq9m7+FwtGaqyCZqC3NyyBkc9z4m+iry4LlqcMWJg==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", + "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", "dev": true, "requires": { "@types/node": "*" @@ -8125,9 +8204,9 @@ "dev": true }, "@types/node": { - "version": "14.14.25", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.25.tgz", - "integrity": "sha512-EPpXLOVqDvisVxtlbvzfyqSsFeQxltFbluZNRndIb8tr9KiBnYNLzrc1N3pyKUCww2RNrfHDViqDWWE1LCJQtQ==", + "version": "14.14.28", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.28.tgz", + "integrity": "sha512-lg55ArB+ZiHHbBBttLpzD07akz0QPrZgUODNakeC09i62dnrywr9mFErHuaPlB6I7z+sEbK+IYmplahvplCj2g==", "dev": true }, "@types/normalize-package-data": { @@ -8137,9 +8216,9 @@ "dev": true }, "@types/prettier": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.2.0.tgz", - "integrity": "sha512-O3SQC6+6AySHwrspYn2UvC6tjo6jCTMMmylxZUFhE1CulVu5l3AxU6ca9lrJDTQDVllF62LIxVSx5fuYL6LiZg==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.2.1.tgz", + "integrity": "sha512-DxZZbyMAM9GWEzXL+BMZROWz9oo6A9EilwwOMET2UVu2uZTqMWS5S69KVtuVKaRjCUpcrOXRalet86/OpG4kqw==", "dev": true }, "@types/sprintf-js": { @@ -8170,13 +8249,13 @@ "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "4.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.15.0.tgz", - "integrity": "sha512-DJgdGZW+8CFUTz5C/dnn4ONcUm2h2T0itWD85Ob5/V27Ndie8hUoX5HKyGssvR8sUMkAIlUc/AMK67Lqa3kBIQ==", + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.15.1.tgz", + "integrity": "sha512-yW2epMYZSpNJXZy22Biu+fLdTG8Mn6b22kR3TqblVk50HGNV8Zya15WAXuQCr8tKw4Qf1BL4QtI6kv6PCkLoJw==", "dev": true, "requires": { - "@typescript-eslint/experimental-utils": "4.15.0", - "@typescript-eslint/scope-manager": "4.15.0", + "@typescript-eslint/experimental-utils": "4.15.1", + "@typescript-eslint/scope-manager": "4.15.1", "debug": "^4.1.1", "functional-red-black-tree": "^1.0.1", "lodash": "^4.17.15", @@ -8186,55 +8265,55 @@ } }, "@typescript-eslint/experimental-utils": { - "version": "4.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.15.0.tgz", - "integrity": "sha512-V4vaDWvxA2zgesg4KPgEGiomWEBpJXvY4ZX34Y3qxK8LUm5I87L+qGIOTd9tHZOARXNRt9pLbblSKiYBlGMawg==", + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.15.1.tgz", + "integrity": "sha512-9LQRmOzBRI1iOdJorr4jEnQhadxK4c9R2aEAsm7WE/7dq8wkKD1suaV0S/JucTL8QlYUPU1y2yjqg+aGC0IQBQ==", "dev": true, "requires": { "@types/json-schema": "^7.0.3", - "@typescript-eslint/scope-manager": "4.15.0", - "@typescript-eslint/types": "4.15.0", - "@typescript-eslint/typescript-estree": "4.15.0", + "@typescript-eslint/scope-manager": "4.15.1", + "@typescript-eslint/types": "4.15.1", + "@typescript-eslint/typescript-estree": "4.15.1", "eslint-scope": "^5.0.0", "eslint-utils": "^2.0.0" } }, "@typescript-eslint/parser": { - "version": "4.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.15.0.tgz", - "integrity": "sha512-L6Dtbq8Bc7g2aZwnIBETpmUa9XDKCMzKVwAArnGp5Mn7PRNFjf3mUzq8UeBjL3K8t311hvevnyqXAMSmxO8Gpg==", + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.15.1.tgz", + "integrity": "sha512-V8eXYxNJ9QmXi5ETDguB7O9diAXlIyS+e3xzLoP/oVE4WCAjssxLIa0mqCLsCGXulYJUfT+GV70Jv1vHsdKwtA==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "4.15.0", - "@typescript-eslint/types": "4.15.0", - "@typescript-eslint/typescript-estree": "4.15.0", + "@typescript-eslint/scope-manager": "4.15.1", + "@typescript-eslint/types": "4.15.1", + "@typescript-eslint/typescript-estree": "4.15.1", "debug": "^4.1.1" } }, "@typescript-eslint/scope-manager": { - "version": "4.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.15.0.tgz", - "integrity": "sha512-CSNBZnCC2jEA/a+pR9Ljh8Y+5TY5qgbPz7ICEk9WCpSEgT6Pi7H2RIjxfrrbUXvotd6ta+i27sssKEH8Azm75g==", + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.15.1.tgz", + "integrity": "sha512-ibQrTFcAm7yG4C1iwpIYK7vDnFg+fKaZVfvyOm3sNsGAerKfwPVFtYft5EbjzByDJ4dj1WD8/34REJfw/9wdVA==", "dev": true, "requires": { - "@typescript-eslint/types": "4.15.0", - "@typescript-eslint/visitor-keys": "4.15.0" + "@typescript-eslint/types": "4.15.1", + "@typescript-eslint/visitor-keys": "4.15.1" } }, "@typescript-eslint/types": { - "version": "4.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.15.0.tgz", - "integrity": "sha512-su4RHkJhS+iFwyqyXHcS8EGPlUVoC+XREfy5daivjLur9JP8GhvTmDipuRpcujtGC4M+GYhUOJCPDE3rC5NJrg==", + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.15.1.tgz", + "integrity": "sha512-iGsaUyWFyLz0mHfXhX4zO6P7O3sExQpBJ2dgXB0G5g/8PRVfBBsmQIc3r83ranEQTALLR3Vko/fnCIVqmH+mPw==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "4.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.15.0.tgz", - "integrity": "sha512-jG6xTmcNbi6xzZq0SdWh7wQ9cMb2pqXaUp6bUZOMsIlu5aOlxGxgE/t6L/gPybybQGvdguajXGkZKSndZJpksA==", + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.15.1.tgz", + "integrity": "sha512-z8MN3CicTEumrWAEB2e2CcoZa3KP9+SMYLIA2aM49XW3cWIaiVSOAGq30ffR5XHxRirqE90fgLw3e6WmNx5uNw==", "dev": true, "requires": { - "@typescript-eslint/types": "4.15.0", - "@typescript-eslint/visitor-keys": "4.15.0", + "@typescript-eslint/types": "4.15.1", + "@typescript-eslint/visitor-keys": "4.15.1", "debug": "^4.1.1", "globby": "^11.0.1", "is-glob": "^4.0.1", @@ -8243,12 +8322,12 @@ } }, "@typescript-eslint/visitor-keys": { - "version": "4.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.15.0.tgz", - "integrity": "sha512-RnDtJwOwFucWFAMjG3ghCG/ikImFJFEg20DI7mn4pHEx3vC48lIAoyjhffvfHmErRDboUPC7p9Z2il4CLb7qxA==", + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.15.1.tgz", + "integrity": "sha512-tYzaTP9plooRJY8eNlpAewTOqtWW/4ff/5wBjNVaJ0S0wC4Gpq/zDVRTJa5bq2v1pCNQ08xxMCndcvR+h7lMww==", "dev": true, "requires": { - "@typescript-eslint/types": "4.15.0", + "@typescript-eslint/types": "4.15.1", "eslint-visitor-keys": "^2.0.0" } }, @@ -9096,12 +9175,12 @@ } }, "eslint": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.19.0.tgz", - "integrity": "sha512-CGlMgJY56JZ9ZSYhJuhow61lMPPjUzWmChFya71Z/jilVos7mR/jPgaEfVGgMBY5DshbKdG8Ezb8FDCHcoMEMg==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.20.0.tgz", + "integrity": "sha512-qGi0CTcOGP2OtCQBgWZlQjcTuP0XkIpYFj25XtRTQSHC+umNnp7UMshr2G8SLsRFYDdAPFeHOsiteadmMH02Yw==", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", + "@babel/code-frame": "7.12.11", "@eslint/eslintrc": "^0.3.0", "ajv": "^6.10.0", "chalk": "^4.0.0", @@ -9113,7 +9192,7 @@ "eslint-utils": "^2.1.0", "eslint-visitor-keys": "^2.0.0", "espree": "^7.3.1", - "esquery": "^1.2.0", + "esquery": "^1.4.0", "esutils": "^2.0.2", "file-entry-cache": "^6.0.0", "functional-red-black-tree": "^1.0.1", @@ -9738,9 +9817,9 @@ } }, "graceful-fs": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.5.tgz", - "integrity": "sha512-kBBSQbz2K0Nyn+31j/w36fUfxkBW9/gfwRWdUY1ULReH3iokVJgddZAFcD1D0xlgTmFxJCbUkUclAlc6/IDJkw==", + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", "dev": true }, "growly": { @@ -11455,6 +11534,12 @@ "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", "dev": true }, + "queue-microtask": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.2.tgz", + "integrity": "sha512-dB15eXv3p2jDlbOiNLyMabYg1/sXvppd8DP2J3EOCQ0AkuSXCW2tP7mnVouVLJKgUMY6yP0kcQDVpLCN13h4Xg==", + "dev": true + }, "react-is": { "version": "17.0.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.1.tgz", @@ -11622,12 +11707,12 @@ "dev": true }, "resolve": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", - "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", "dev": true, "requires": { - "is-core-module": "^2.1.0", + "is-core-module": "^2.2.0", "path-parse": "^1.0.6" } }, @@ -11688,10 +11773,13 @@ "dev": true }, "run-parallel": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.10.tgz", - "integrity": "sha512-zb/1OuZ6flOlH6tQyMPUrE3x3Ulxjlo9WIVXR4yVYi4H9UXQaeIsPbLn2R3O3vQCnDKkAl2qHiuocKKX4Tz/Sw==", - "dev": true + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } }, "safe-buffer": { "version": "5.1.2", @@ -12495,9 +12583,9 @@ }, "dependencies": { "ajv": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.0.4.tgz", - "integrity": "sha512-xzzzaqgEQfmuhbhAoqjJ8T/1okb6gAzXn/eQRNpAN1AEUoHJTNF9xCDRTtf/s3SKldtZfa+RJeTs+BQq+eZ/sw==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.1.1.tgz", + "integrity": "sha512-ga/aqDYnUy/o7vbsRTFhhTsNeXiYb5JWDIcRIeZfwRNCefwjNTVYCGdGSUrEmiu3yDK3vFvNbgJxvrQW4JXrYQ==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -12681,9 +12769,9 @@ } }, "typescript": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz", - "integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.5.tgz", + "integrity": "sha512-6OSu9PTIzmn9TCDiovULTnET6BgXtDYL4Gg4szY+cGsc3JP1dQL8qvE8kShTRx1NIw4Q9IBHlwODjkjWEtMUyA==", "dev": true }, "union-value": { @@ -12973,9 +13061,9 @@ } }, "yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==" + "version": "20.2.5", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.5.tgz", + "integrity": "sha512-jYRGS3zWy20NtDtK2kBgo/TlAoy5YUuhD9/LZ7z7W4j1Fdw2cqD0xEEclf8fxc8xjD6X5Qr+qQQwCEsP8iRiYg==" } } } diff --git a/abap-api-tools/package.json b/abap-api-tools/package.json index 68aca5f4..e2818629 100644 --- a/abap-api-tools/package.json +++ b/abap-api-tools/package.json @@ -1,7 +1,7 @@ { "name": "abap-api-tools", "description": "ABAP api tools", - "version": "1.6.4", + "version": "1.7.0", "homepage": "https://github.com/sap/fundamental-tools", "author": "SAP", "license": "Apache-2.0", diff --git a/abap-api-tools/src/ts/abap.ts b/abap-api-tools/src/ts/abap.ts index d3bf7743..671d5325 100644 --- a/abap-api-tools/src/ts/abap.ts +++ b/abap-api-tools/src/ts/abap.ts @@ -7,20 +7,22 @@ import fs from "fs"; import path from "path"; import yargs from "yargs"; +import { RfcConnectionParameters } from "node-rfc"; import { UIFrameworks, UIFrameworksAll, UIFrameworksLocal, Languages, + DefaultLanguage, DefaultFolder, runningInDocker, DockerVolume, } from "./constants"; import { AnnotationsType, Backend } from "./backend"; -import { Frontend } from "./frontend"; +import { Frontend, FrontendResult } from "./frontend"; import { yamlLoad, log, makeDir, deleteFile, getTimestamp } from "./utils"; -export let Signature: string; +export let Signature = `abap api`; export const Command = Object.freeze({ call: "call", @@ -31,26 +33,36 @@ export const Command = Object.freeze({ languages: "languages", }); -type ApiListType = Record; -export interface Arguments { - [argName: string]: unknown; +export type ApiListType = Record; + +export type Destination = string | RfcConnectionParameters; +export { RfcConnectionParameters }; + +export type Arguments = { + //[argName: string]: unknown; _: (string | number)[]; $0: string; - rfm: string[]; - c: string | string[]; - apilist: ApiListType; cmd: string; - ui: string; - debug: boolean; - dest: string; output: string; lang: string; - save: boolean; - textOnly: string; -} + apilist?: ApiListType; + rfm?: string[]; + c?: string | string[]; + debug?: boolean; + dest?: Destination; + save?: boolean; + textOnly?: string; + ui?: string; + runInBg?: boolean; +}; +export type CliResult = { + annotations?: AnnotationsType; + frontend?: FrontendResult; +}; class CliHandler { private argv: Arguments; + constructor(argv: Arguments) { log.debug(argv); log.debug(DefaultFolder); @@ -72,7 +84,7 @@ class CliHandler { } // add rfms - if (argv.rfm.length) { + if (argv.rfm && argv.rfm.length) { const rfm = new Set(); for (const rfm_name of argv.rfm) { rfm.add(rfm_name.toUpperCase()); @@ -83,12 +95,14 @@ class CliHandler { } this.argv = argv; + log.debug(argv); } - async run() { - try { + async run(): Promise { + const result: CliResult = {}; + if (this.argv.apilist) { for (const api_name of Object.keys(this.argv.apilist)) { - let abap: AnnotationsType = { + let annotations: AnnotationsType = { parameters: {}, fields: {}, stat: {}, @@ -96,31 +110,32 @@ class CliHandler { if ([Command.call, Command.get].includes(this.argv.cmd)) { log.debug(`backend run ${api_name}`); const backend = new Backend(api_name, this.argv); - abap = await backend.parse(); + annotations = await backend.parse(); + result[api_name] = { annotations: annotations }; } if ( (this.argv.cmd === Command.get && !this.argv.textOnly) || [Command.call, Command.make].includes(this.argv.cmd) ) { - const frontend = new Frontend(api_name, abap, this.argv); + const frontend = new Frontend(api_name, annotations, this.argv); log.debug(`frontend run ${api_name}`); - frontend.parse(); + result[api_name]["frontend"] = frontend.parse(); } } - } catch (ex) { - log.info(ex); } + + return result; } - removeConfiguration(ui: string) { + removeConfiguration(ui: string): void { for (const fn of [`${ui}-abap`, `${ui}`]) { deleteFile(path.join(DefaultFolder.userConfig, `${fn}.yaml`)); } log.info(`Local configuration removed: ${ui}`); } - copyConfiguration(source: string, target = "") { + copyConfiguration(source: string, target = ""): void { makeDir(DefaultFolder.userConfig); if (target.length === 0) target = source; for (const suffix of ["", "-abap"]) { @@ -139,278 +154,351 @@ class CliHandler { } } -export const argv = yargs(process.argv.slice(2)) - .strict(true) - .demandCommand() - .command({ - command: `${Command.call} `, - describe: "ABAP function module call template", - builder: (y) => { - return y - .positional("dest", { - type: "string", - describe: "ABAP system destination id, from sapnwrfc.ini", - }) - .positional("rfm", { - describe: "BAPI/RFM name(s)", - }) - .option("l", { - alias: "lang", - describe: "ABAP texts language", - type: "string", - default: "en", - nargs: 1, - }) - .option("f", { - alias: "sort-fields", - describe: "Sort field names of structures and tables", - type: "boolean", - default: false, - nargs: 0, - }) - .option("s", { - alias: "save", - describe: "Save to local file", - type: "boolean", - default: false, - nargs: 0, - }) - .option("o", { - alias: "output", - describe: "Output folder", - type: "string", - default: "", - nargs: 1, - }) - .option("d", { - alias: "debug", - describe: "Detailed logging", - type: "boolean", - default: false, - nargs: 0, - }); - }, - handler: (argv) => { - new CliHandler(argv as Arguments).run(); - }, - }) - .command({ - command: `${Command.get} [rfm...]`, - describe: "ABAP API annotations", - builder: (y) => { - return y - .positional("dest", { - type: "string", - describe: "ABAP system destination id, from sapnwrfc.ini", - }) - .positional("rfm", { - describe: "BAPI/RFM name(s)", - }) - .option("l", { - alias: "lang", - describe: "ABAP texts language", - type: "string", - default: "en", - nargs: 1, - }) - .option("c", { - alias: "catalog", - describe: "Read RFM names from file", - type: "string", - nargs: 1, - }) - .option("t", { - alias: "text-only", - describe: "Get only texts in a given language", - type: "string", - default: "", - nargs: 1, - }) - .option("o", { - alias: "output", - describe: "Output folder", - type: "string", - default: DefaultFolder.output, - nargs: 1, - }) - .option("d", { - alias: "debug", - describe: "Detailed logging", - type: "boolean", - default: false, - nargs: 0, - }); - }, - handler: (argv) => { - return new CliHandler(argv as Arguments).run(); - }, - }) - .command({ - command: `${Command.make} [rfm...]`, - describe: "Create ui elements", - builder: (y) => { - return y - .positional("ui", { - choices: UIFrameworksAll, - describe: `ui framework`, - }) - .positional("rfm", { - describe: "BAPI/RFM name(s)", - }) - .option("c", { - alias: "catalog", - describe: "Read RFM names from file", - nargs: 1, - }) - .option("f", { - alias: "sort-fields", - describe: "Sort field names of structures and tables", - type: "boolean", - default: false, - nargs: 0, - }) - .option("o", { - alias: "output", - describe: "Output folder", - type: "string", - default: DefaultFolder.output, - nargs: 1, - }) - .option("d", { - alias: "debug", - describe: "Detailed logging", - type: "boolean", - default: false, - nargs: 0, - }); - }, - handler: (argv) => { - new CliHandler(argv as Arguments).run(); - }, - }) - .command({ - command: `${Command.languages}`, - describe: "Supported languages", - handler: () => { - log.info(Languages); - }, - }) - .command({ - command: `${Command.copy} [to]`, - describe: `Copy ui configuration to local folder ${DefaultFolder.userConfig}`, - builder: (y) => { - return y - .positional("ui", { - choices: UIFrameworks, - describe: "ui framework name", - }) - .positional("to", { - default: "", - describe: "New name for custom configuration", - }) - .option("d", { - alias: "debug", - describe: "Detailed logging", - type: "boolean", - default: false, - nargs: 0, - }); - }, - handler: (argv) => { - new CliHandler(argv as Arguments).copyConfiguration( - argv.ui as string, - argv.to as string - ); - }, - }) - .command({ - command: `${Command.remove} `, - describe: "Remove local ui configuration", - builder: (y) => { - return y - .positional("ui", { - choices: UIFrameworksLocal, - describe: "ui framework", - }) - .option("d", { - alias: "debug", - describe: "Detailed logging", - type: "boolean", - default: false, - nargs: 0, - }); - }, - handler: (argv) => { - new CliHandler(argv as Arguments).removeConfiguration(argv.ui as string); - }, - }) - .check((argv) => { - // critical error, docker volume not mounted - if (runningInDocker && !fs.existsSync(DockerVolume)) { - throw new Error( - `Docker volume ${DockerVolume} not mounted. Re-build the container: https://github.com/SAP/fundamental-tools/tree/main/docker#abap-api-tools` - ); +export class CliApi { + private options = { lang: DefaultLanguage, debug: false }; + + async call( + dest: Destination, + rfm_names: string | string[], + options?: { lang?: string; debug?: boolean } + ): Promise { + if (options) { + Object.assign(this.options, options); } - // set command - argv.cmd = argv._[0]; + log.setDefaultLevel( + this.options.debug ? log.levels.DEBUG : log.levels.SILENT + ); + + const args: Arguments = { + _: [Command.call], + $0: "abap", + rfm: typeof rfm_names === "string" ? [rfm_names] : rfm_names, + cmd: Command.call, + dest: dest, + output: "", + lang: this.options.lang, + debug: this.options.debug, + runInBg: true, + }; + + const cli = new CliHandler(args); - // set log level first - if (argv.d) { - log.setDefaultLevel(log.levels["DEBUG"]); - } else { - log.setDefaultLevel(log.levels["INFO"]); + const result = await cli.run(); + + return result[""]; + } + + async get( + dest: Destination, + rfm_names: string | string[], + options?: { lang?: string; debug?: boolean } + ): Promise { + if (options) { + Object.assign(this.options, options); } - log.debug(process.argv); + log.setDefaultLevel( + this.options.debug ? log.levels.DEBUG : log.levels.SILENT + ); + + const args: Arguments = { + _: [Command.get], + $0: "abap", + rfm: typeof rfm_names === "string" ? [rfm_names] : rfm_names, + cmd: Command.get, + dest: dest, + output: "", + lang: this.options.lang, + debug: this.options.debug, + runInBg: true, + }; + + const cli = new CliHandler(args); - // check duplicates - for (const flag of ["lang", "output", "text-only"]) { - if (Array.isArray(argv[flag])) { - throw new Error(`Too many arguments: ${flag}`); + const result = await cli.run(); + + return result[""]; + } +} + +// invoked via CLI +if (require.main === module) + yargs(process.argv.slice(2)) + .strict(true) + .demandCommand() + .command({ + command: `${Command.call} `, + describe: "ABAP function module call template", + builder: (y) => { + return y + .positional("dest", { + type: "string", + describe: "ABAP system destination id, from sapnwrfc.ini", + }) + .positional("rfm", { + describe: "BAPI/RFM name(s)", + }) + .option("l", { + alias: "lang", + describe: "ABAP texts language", + type: "string", + default: DefaultLanguage, + nargs: 1, + }) + .option("f", { + alias: "sort-fields", + describe: "Sort field names of structures and tables", + type: "boolean", + default: false, + nargs: 0, + }) + .option("s", { + alias: "save", + describe: "Save to local file", + type: "boolean", + default: false, + nargs: 0, + }) + .option("o", { + alias: "output", + describe: "Output folder", + type: "string", + default: "", + nargs: 1, + }) + .option("d", { + alias: "debug", + describe: "Detailed logging", + type: "boolean", + default: false, + nargs: 0, + }); + }, + handler: (argv) => { + new CliHandler(argv as Arguments).run(); + }, + }) + .command({ + command: `${Command.get} [rfm...]`, + describe: "ABAP API annotations", + builder: (y) => { + return y + .positional("dest", { + type: "string", + describe: "ABAP system destination id, from sapnwrfc.ini", + }) + .positional("rfm", { + describe: "BAPI/RFM name(s)", + }) + .option("l", { + alias: "lang", + describe: "ABAP texts language", + type: "string", + default: DefaultLanguage, + nargs: 1, + }) + .option("c", { + alias: "catalog", + describe: "Read RFM names from file", + type: "string", + nargs: 1, + }) + .option("t", { + alias: "text-only", + describe: "Get only texts in a given language", + type: "string", + default: "", + nargs: 1, + }) + .option("o", { + alias: "output", + describe: "Output folder", + type: "string", + default: DefaultFolder.output, + nargs: 1, + }) + .option("d", { + alias: "debug", + describe: "Detailed logging", + type: "boolean", + default: false, + nargs: 0, + }); + }, + handler: (argv) => { + return new CliHandler(argv as Arguments).run(); + }, + }) + .command({ + command: `${Command.make} [rfm...]`, + describe: "Create ui elements", + builder: (y) => { + return y + .positional("ui", { + choices: UIFrameworksAll, + describe: `ui framework`, + }) + .positional("rfm", { + describe: "BAPI/RFM name(s)", + }) + .option("c", { + alias: "catalog", + describe: "Read RFM names from file", + nargs: 1, + }) + .option("f", { + alias: "sort-fields", + describe: "Sort field names of structures and tables", + type: "boolean", + default: false, + nargs: 0, + }) + .option("o", { + alias: "output", + describe: "Output folder", + type: "string", + default: DefaultFolder.output, + nargs: 1, + }) + .option("d", { + alias: "debug", + describe: "Detailed logging", + type: "boolean", + default: false, + nargs: 0, + }); + }, + handler: (argv) => { + new CliHandler(argv as Arguments).run(); + }, + }) + .command({ + command: `${Command.languages}`, + describe: "Supported languages", + handler: () => { + log.info(Languages); + }, + }) + .command({ + command: `${Command.copy} [to]`, + describe: `Copy ui configuration to local folder ${DefaultFolder.userConfig}`, + builder: (y) => { + return y + .positional("ui", { + choices: UIFrameworks, + describe: "ui framework name", + }) + .positional("to", { + default: "", + describe: "New name for custom configuration", + }) + .option("d", { + alias: "debug", + describe: "Detailed logging", + type: "boolean", + default: false, + nargs: 0, + }); + }, + handler: (argv) => { + new CliHandler(argv as Arguments).copyConfiguration( + argv.ui as string, + argv.to as string + ); + }, + }) + .command({ + command: `${Command.remove} `, + describe: "Remove local ui configuration", + builder: (y) => { + return y + .positional("ui", { + choices: UIFrameworksLocal, + describe: "ui framework", + }) + .option("d", { + alias: "debug", + describe: "Detailed logging", + type: "boolean", + default: false, + nargs: 0, + }); + }, + handler: (argv) => { + new CliHandler(argv as Arguments).removeConfiguration( + argv.ui as string + ); + }, + }) + .check((argv) => { + // critical error, docker volume not mounted + if (runningInDocker && !fs.existsSync(DockerVolume)) { + throw new Error( + `Docker volume ${DockerVolume} not mounted. Re-build the container: https://github.com/SAP/fundamental-tools/tree/main/docker#abap-api-tools` + ); } - } - if (argv.output) { - // if output folder given, file should be saved - argv.s = true; - argv.save = true; - } + // set command + argv.cmd = argv._[0]; - // text only with lang key - if (argv["text-only"]) { - if ( - process.argv.indexOf("-l") !== -1 || - process.argv.indexOf("--lang") !== -1 - ) { - throw new Error(`Text-only option is not allowed with lang options`); + // set log level first + log.setDefaultLevel(argv.d ? log.levels.DEBUG : log.levels.INFO); + + log.debug(process.argv); + + // check duplicates + for (const flag of ["lang", "output", "text-only"]) { + if (Array.isArray(argv[flag])) { + throw new Error(`Too many arguments: ${flag}`); + } } - // lang set by text-only - argv.l = argv.textOnly; - argv.lang = argv.textOnly; - } - // check language - if (argv.lang && !Object.keys(Languages).includes(argv.lang as string)) { - throw new Error(`Language not supported: ${argv.lang}`); - } + if (argv.output) { + // if output folder given, file should be saved + argv.s = true; + argv.save = true; + } - // output folder - if ("output" in argv && (argv.output as string).substring(0, 2) !== "./") { - // add leading ./ - argv.output = `./${argv.output}`; - argv.o = argv.output; - } + // text only with lang key + if (argv["text-only"]) { + if ( + process.argv.indexOf("-l") !== -1 || + process.argv.indexOf("--lang") !== -1 + ) { + throw new Error(`Text-only option is not allowed with lang options`); + } + // lang set by text-only + argv.l = argv.textOnly; + argv.lang = argv.textOnly; + } - // Write CLI version to output signature string - yargs.parse( - "--version", - (err: Error | undefined, argv: { $0: string }, output: string) => { - Signature = `${path.basename(argv.$0)} ${output} at: ${getTimestamp()}`; + // check language + if (argv.lang && !Object.keys(Languages).includes(argv.lang as string)) { + throw new Error(`Language not supported: ${argv.lang}`); } - ); - return true; - }) - .help() - .version().argv; + // output folder + if ( + "output" in argv && + (argv.output as string).substring(0, 2) !== "./" + ) { + // add leading ./ + argv.output = `./${argv.output}`; + argv.o = argv.output; + } + + // Write CLI version to output signature string + yargs.parse( + "--version", + (err: Error | undefined, argv: { $0: string }, output: string) => { + Signature = `${path.basename( + argv.$0 + )} ${output} at: ${getTimestamp()}`; + } + ); + + return true; + }) + .help() + .version().argv; diff --git a/abap-api-tools/src/ts/backend.ts b/abap-api-tools/src/ts/backend.ts index a5149fcb..6fdd8433 100644 --- a/abap-api-tools/src/ts/backend.ts +++ b/abap-api-tools/src/ts/backend.ts @@ -8,7 +8,13 @@ import chalk from "chalk"; import fs from "fs"; import path from "path"; import { sprintf } from "sprintf-js"; -import { Client, RfcParameterValue, RfcTable, RfcStructure } from "node-rfc"; +import { + Client, + RfcParameterValue, + RfcTable, + RfcStructure, + RfcConnectionParameters, +} from "node-rfc"; import { Command, Arguments } from "./abap"; import { Languages, @@ -142,37 +148,59 @@ export class Backend { private Texts = {} as yamlTextsType; private client = {} as Client; + private clientConnectionParameters: RfcConnectionParameters; + private systemId = ""; constructor(api_name: string, argv: Arguments) { this.argv = argv; this.api_name = api_name; - this.apilist = this.argv.apilist[api_name]; + this.apilist = argv.apilist ? argv.apilist[api_name] : []; this.alpha = new Alpha(); this.SPRAS = Languages[this.argv.lang].spras; this.Helps = {}; this.Stat = {}; + this.clientConnectionParameters = {}; + log.debug( - `backend: ${this.api_name} dest: ${this.argv.dest} lang: ${argv.lang} : ${this.SPRAS} api: ${this.apilist}` + `backend: ${this.api_name} systemId: ${this.systemId} lang: ${argv.lang} : ${this.SPRAS} api: ${this.apilist}` ); + if (this.argv.dest) { + if (typeof this.argv.dest === "string") { + this.clientConnectionParameters = { dest: this.argv.dest }; + this.systemId = this.argv.dest; + } else { + this.clientConnectionParameters = this.argv.dest; + this.systemId = + this.clientConnectionParameters.ashost || + this.clientConnectionParameters.msserv || + this.clientConnectionParameters.gwserv || + this.clientConnectionParameters.snc_partnername || + ""; + } + } + // check if search help api configured - if (this.argv.dest && this.argv.cmd === Command.get) { + if (this.argv.cmd === Command.get) { try { const systemYamlPath = path.join( DefaultFolder.userConfig, "systems.yaml" ); const systems = yamlLoad(systemYamlPath) as SystemsYamlType; + if (!systems) { log.info(`systems.yaml not found: ${systemYamlPath}`); - } else if (!systems[this.argv.dest]) { - log.info(`system ${this.argv.dest} not found in systems.yaml`); - } else if (!systems[this.argv.dest].search_help_api) { - log.info(`search help api not configured for ${this.argv.dest}`); + } else if (!this.systemId) { + log.info("System key not found in connection parameters"); + } else if (!systems[this.systemId]) { + log.info(`system ${this.systemId} not found in systems.yaml`); + } else if (!systems[this.systemId].search_help_api) { + log.info(`search help api not configured for ${this.systemId}`); } else { - this.search_help_api = systems[this.argv.dest].search_help_api; + this.search_help_api = systems[this.systemId].search_help_api; for (const [apiKey, apiName] of Object.entries( this.search_help_api @@ -545,7 +573,7 @@ export class Backend { if (runningInDocker) { addon.setIniFileDirectory(DockerVolume); } - this.client = new addon.Client({ dest: this.argv.dest }); + this.client = new addon.Client(this.clientConnectionParameters); } catch (ex) { throw new Error( [ @@ -577,7 +605,7 @@ export class Backend { } log.info( - `\n${chalk.bold(this.api_name)} ${this.argv.dest} (${this.argv.lang}) ${ + `\n${chalk.bold(this.api_name)} ${this.systemId} (${this.argv.lang}) ${ this.argv.textOnly ? "only texts" : "" } ${this.getSearchHelps ? "search helps" : ""}\n`.replace(/ +/g, " ") ); @@ -821,7 +849,7 @@ export class Backend { usage: usage, }; - if (this.argv.cmd === Command.get) { + if (!this.argv.runInBg && this.argv.cmd === Command.get) { this.annotations_write(abap, this.Texts, Boolean(this.argv.textOnly)); } diff --git a/abap-api-tools/src/ts/constants.ts b/abap-api-tools/src/ts/constants.ts index 0d32e1ad..c634b42b 100644 --- a/abap-api-tools/src/ts/constants.ts +++ b/abap-api-tools/src/ts/constants.ts @@ -85,6 +85,8 @@ export const Languages = Object.freeze({ vi: { spras: "쁩", text: "Vietnamese" }, }); +export const DefaultLanguage = "en"; + // Parameter types export const ParamType = Object.freeze({ var: "var", diff --git a/abap-api-tools/src/ts/frontend.ts b/abap-api-tools/src/ts/frontend.ts index 4afa72da..66b864f2 100644 --- a/abap-api-tools/src/ts/frontend.ts +++ b/abap-api-tools/src/ts/frontend.ts @@ -86,8 +86,10 @@ type UiConfigTableType = { type UiConfigType = Record; +export type FrontendResult = Record; export class Frontend { private api_name: string; + private apilist: string[]; private abap: AnnotationsType; private argv: Arguments; @@ -101,9 +103,10 @@ export class Frontend { private abapConfig: AbapConfigType = {}; constructor(api_name: string, abap: AnnotationsType, argv: Arguments) { - this.api_name = api_name; this.abap = abap; this.argv = argv; + this.api_name = api_name; + this.apilist = argv.apilist ? argv.apilist[api_name] : []; // abap if (!this.abap || isEmpty(this.abap.parameters)) { @@ -292,7 +295,7 @@ export class Frontend { return result; } - parse(): void { + parse(): FrontendResult { log.info( `\nfrontend: ${this.argv.ui || ""} using ${ this.configPath.abapLocal ? this.configPath.abap : "default abap.yaml" @@ -304,7 +307,9 @@ export class Frontend { }; field names sorted: ${this.argv["sort-fields"] ? "yes" : "no"}\n` ); - for (const rfm_name of this.argv.apilist[this.api_name]) { + const result: FrontendResult = {}; + + for (const rfm_name of this.apilist) { // check local annotations if (!this.abap.parameters[rfm_name]) { log.info(chalk.red(`${rfm_name} annotations not found`)); @@ -343,7 +348,7 @@ export class Frontend { rfm_name.replace(/\//g, "_").toLowerCase() ); - const jsWriter = new Writer(`${fileName}.js`, this.argv.save); + const jsWriter = new Writer(`${fileName}.js`, this.argv.save as boolean); let htmlWriter: Writer | undefined; @@ -361,7 +366,7 @@ export class Frontend { jsWriter.write(`const parameters = {`); if (this.argv.ui) { - htmlWriter = new Writer(`${fileName}.html`, this.argv.save); + htmlWriter = new Writer(`${fileName}.html`, this.argv.save as boolean); // // html header // @@ -516,9 +521,10 @@ export class Frontend { } } - jsWriter.save(); - if (htmlWriter) htmlWriter.save(); + result[rfm_name] = { js: jsWriter.save() }; + if (htmlWriter) result[rfm_name].html = htmlWriter.save(); } + return result; } table_init( diff --git a/abap-api-tools/src/ts/utils.ts b/abap-api-tools/src/ts/utils.ts index 97d3fa03..bbdcca87 100644 --- a/abap-api-tools/src/ts/utils.ts +++ b/abap-api-tools/src/ts/utils.ts @@ -111,8 +111,8 @@ export class Writer { this.output.push(this.NEWLINE); } - save(): void { - const ms = this.output.join(this.NEWLINE); + save(): string { + const ms: string = this.output.join(this.NEWLINE); if (this.saveToFile) { const stream = fs.createWriteStream(this.fileName); stream.once("open", () => { @@ -122,5 +122,6 @@ export class Writer { } else { log.info(ms); } + return ms; } } diff --git a/abap-api-tools/tests/cliapi.spec.js b/abap-api-tools/tests/cliapi.spec.js new file mode 100644 index 00000000..844abaa2 --- /dev/null +++ b/abap-api-tools/tests/cliapi.spec.js @@ -0,0 +1,591 @@ +// SPDX-FileCopyrightText: 2014 SAP SE Srdjan Boskovic +// +// SPDX-License-Identifier: Apache-2.0 + +const CliApi = require("../dist/abap").CliApi; + +("use strict"); + +describe("Pool Options", () => { + const api = new CliApi(); + + const cp = { + user: "demo", + passwd: "welcome", + ashost: "10.68.110.51", + sysnr: "00", + client: "620", + lang: "EN", + }; + + const RESULT1 = { + annotations: { + alpha: { all: [], rfm: {} }, + fields: { + SYST: { + LISEL: { + format: { + DATATYPE: "CHAR", + DOMNAME: "SYCHAR255", + INTTYPE: "C", + LENG: 255, + OUTPUTLEN: 255, + ROLLNAME: "SYST_LISEL", + }, + text: { + FIELDTEXT: "ABAP System Field: Content of Selected List Line", + REPTEXT: "Line Content", + SCRTEXT_L: "Line Content", + SCRTEXT_M: "Line Content", + SCRTEXT_S: "Line", + }, + }, + }, + }, + helps: {}, + parameters: { + STFC_CONNECTION: { + ECHOTEXT: { + FIELDNAME: "LISEL", + PARAMCLASS: "E", + PARAMTEXT: "", + TABNAME: "SYST", + functionName: "STFC_CONNECTION", + paramName: "ECHOTEXT", + paramType: "var", + required: true, + }, + REQUTEXT: { + FIELDNAME: "LISEL", + PARAMCLASS: "I", + PARAMTEXT: "", + TABNAME: "SYST", + functionName: "STFC_CONNECTION", + paramName: "REQUTEXT", + paramType: "var", + required: true, + }, + RESPTEXT: { + FIELDNAME: "LISEL", + PARAMCLASS: "E", + PARAMTEXT: "", + TABNAME: "SYST", + functionName: "STFC_CONNECTION", + paramName: "RESPTEXT", + paramType: "var", + required: true, + }, + }, + }, + stat: { + STFC_CONNECTION: { exception: 0, struct: 0, table: 0, var: 3 }, + }, + usage: {}, + }, + frontend: { + STFC_CONNECTION: { + js: + "//\n" + + "// STFC_CONNECTION var: 3 struct: 0 table: 0 exception: 0\n" + + "//\n" + + "// abap api\n" + + "//\n" + + "\n" + + "// prettier-ignore\n" + + "const parameters = {\n" + + "\n" + + "// IMPORT PARAMETERS\n" + + "\n" + + 'REQUTEXT : "", // CHAR (255) no text (en)\n' + + "\n" + + "// EXPORT PARAMETERS\n" + + "\n" + + '// ECHOTEXT : "", // CHAR (255) no text (en)\n' + + '// RESPTEXT : "", // CHAR (255) no text (en)\n' + + "};\n" + + "\n" + + 'const result = await client.call("STFC_CONNECTION", parameters);\n' + + "\n" + + "//\n" + + "// IMPORT PARAMETERS\n" + + "//\n" + + "\n" + + "\n" + + "//\n" + + "// EXPORT PARAMETERS\n" + + "//\n", + }, + }, + }; + + const RESULT2 = { + annotations: { + alpha: { all: [], rfm: {} }, + fields: { + RFCTEST: { + RFCCHAR1: { + format: { + DATATYPE: "CHAR", + DOMNAME: "RFCCHAR1", + INTTYPE: "C", + LENG: 1, + LOWERCASE: "X", + OUTPUTLEN: 1, + ROLLNAME: "RFCCHAR1", + }, + text: { + FIELDTEXT: "Character field of length 1", + REPTEXT: "char1", + SCRTEXT_L: "char1", + SCRTEXT_M: "char1", + SCRTEXT_S: "char1", + }, + }, + RFCCHAR2: { + format: { + DATATYPE: "CHAR", + DOMNAME: "RFCCHAR2", + INTTYPE: "C", + LENG: 2, + OUTPUTLEN: 2, + ROLLNAME: "RFCCHAR2", + }, + text: { + FIELDTEXT: "Character field of length 2", + REPTEXT: "char2", + SCRTEXT_L: "char2", + SCRTEXT_M: "char2", + SCRTEXT_S: "char2", + }, + }, + RFCCHAR4: { + format: { + DATATYPE: "CHAR", + DOMNAME: "RFCCHAR4", + INTTYPE: "C", + LENG: 4, + LOWERCASE: "X", + OUTPUTLEN: 4, + ROLLNAME: "RFCCHAR4", + }, + text: { + FIELDTEXT: "Character field of length 4", + REPTEXT: "char4", + SCRTEXT_L: "char4", + SCRTEXT_M: "char4", + SCRTEXT_S: "char4", + }, + }, + RFCDATA1: { + format: { + DATATYPE: "CHAR", + DOMNAME: "TEXT50", + INTTYPE: "C", + LENG: 50, + LOWERCASE: "X", + OUTPUTLEN: 50, + ROLLNAME: "CHAR50", + }, + text: { + FIELDTEXT: "Comment", + REPTEXT: "c", + SCRTEXT_L: "c", + SCRTEXT_M: "c", + SCRTEXT_S: "c", + }, + }, + RFCDATA2: { + format: { + DATATYPE: "CHAR", + DOMNAME: "TEXT50", + INTTYPE: "C", + LENG: 50, + LOWERCASE: "X", + OUTPUTLEN: 50, + ROLLNAME: "CHAR50", + }, + text: { + FIELDTEXT: "Comment", + REPTEXT: "c", + SCRTEXT_L: "c", + SCRTEXT_M: "c", + SCRTEXT_S: "c", + }, + }, + RFCDATE: { + format: { + DATATYPE: "DATS", + DOMNAME: "RFCDATE", + INTTYPE: "D", + LENG: 8, + OUTPUTLEN: 10, + ROLLNAME: "RFCDATE", + }, + text: { + FIELDTEXT: "Date field", + REPTEXT: "Date", + SCRTEXT_L: "Date", + SCRTEXT_M: "Date", + SCRTEXT_S: "Date", + }, + }, + RFCFLOAT: { + format: { + DATATYPE: "FLTP", + DECIMALS: 16, + DOMNAME: "RFCFLOAT", + INTTYPE: "F", + LENG: 16, + OUTPUTLEN: 22, + ROLLNAME: "RFCFLOAT", + }, + text: { + FIELDTEXT: "Float field", + REPTEXT: "Float", + SCRTEXT_L: "Float", + SCRTEXT_M: "Float", + SCRTEXT_S: "Float", + }, + }, + RFCHEX3: { + format: { + DATATYPE: "RAW", + DOMNAME: "RFCHEX3", + INTTYPE: "X", + LENG: 3, + OUTPUTLEN: 6, + ROLLNAME: "RFCHEX3", + }, + text: { + FIELDTEXT: "HEX field of length 3", + REPTEXT: "hex3", + SCRTEXT_L: "hex3", + SCRTEXT_M: "hex3", + SCRTEXT_S: "hex3", + }, + }, + RFCINT1: { + format: { + DATATYPE: "INT1", + DOMNAME: "RFCINT1", + INTTYPE: "b", + LENG: 3, + OUTPUTLEN: 3, + ROLLNAME: "RFCINT1", + }, + text: { + FIELDTEXT: "INT1 field", + REPTEXT: "INT1", + SCRTEXT_L: "INT1", + SCRTEXT_M: "INT1", + SCRTEXT_S: "INT1", + }, + }, + RFCINT2: { + format: { + DATATYPE: "INT2", + DOMNAME: "RFCINT2", + INTTYPE: "s", + LENG: 5, + OUTPUTLEN: 5, + ROLLNAME: "RFCINT2", + }, + text: { + FIELDTEXT: "INT2 field", + REPTEXT: "INT2", + SCRTEXT_L: "INT2", + SCRTEXT_M: "INT2", + SCRTEXT_S: "INT2", + }, + }, + RFCINT4: { + format: { + DATATYPE: "INT4", + DOMNAME: "RFCINT4", + INTTYPE: "I", + LENG: 10, + OUTPUTLEN: 10, + ROLLNAME: "RFCINT4", + }, + text: { + FIELDTEXT: "INT4 field", + REPTEXT: "INT4", + SCRTEXT_L: "INT4", + SCRTEXT_M: "INT4", + SCRTEXT_S: "INT4", + }, + }, + RFCTIME: { + format: { + DATATYPE: "TIMS", + DOMNAME: "RFCTIME", + INTTYPE: "T", + LENG: 6, + OUTPUTLEN: 8, + ROLLNAME: "RFCTIME", + }, + text: { + FIELDTEXT: "Validity Period", + REPTEXT: "Validity Period", + SCRTEXT_L: "Validity Period", + SCRTEXT_M: "Validity Period", + SCRTEXT_S: "Duration", + }, + }, + }, + SYST: { + LISEL: { + format: { + DATATYPE: "CHAR", + DOMNAME: "SYCHAR255", + INTTYPE: "C", + LENG: 255, + OUTPUTLEN: 255, + ROLLNAME: "SYST_LISEL", + }, + text: { + FIELDTEXT: "ABAP System Field: Content of Selected List Line", + REPTEXT: "Line Content", + SCRTEXT_L: "Line Content", + SCRTEXT_M: "Line Content", + SCRTEXT_S: "Line", + }, + }, + }, + }, + helps: {}, + parameters: { + STFC_CONNECTION: { + ECHOTEXT: { + FIELDNAME: "LISEL", + PARAMCLASS: "E", + PARAMTEXT: "", + TABNAME: "SYST", + functionName: "STFC_CONNECTION", + paramName: "ECHOTEXT", + paramType: "var", + required: true, + }, + REQUTEXT: { + FIELDNAME: "LISEL", + PARAMCLASS: "I", + PARAMTEXT: "", + TABNAME: "SYST", + functionName: "STFC_CONNECTION", + paramName: "REQUTEXT", + paramType: "var", + required: true, + }, + RESPTEXT: { + FIELDNAME: "LISEL", + PARAMCLASS: "E", + PARAMTEXT: "", + TABNAME: "SYST", + functionName: "STFC_CONNECTION", + paramName: "RESPTEXT", + paramType: "var", + required: true, + }, + }, + STFC_STRUCTURE: { + ECHOSTRUCT: { + PARAMCLASS: "E", + PARAMTEXT: "Exporting structure", + TABNAME: "RFCTEST", + functionName: "STFC_STRUCTURE", + paramName: "ECHOSTRUCT", + paramType: "struct", + required: true, + }, + IMPORTSTRUCT: { + PARAMCLASS: "I", + PARAMTEXT: "Importing structure", + TABNAME: "RFCTEST", + functionName: "STFC_STRUCTURE", + paramName: "IMPORTSTRUCT", + paramType: "struct", + required: true, + }, + RESPTEXT: { + FIELDNAME: "LISEL", + PARAMCLASS: "E", + PARAMTEXT: "Exporting response message", + TABNAME: "SYST", + functionName: "STFC_STRUCTURE", + paramName: "RESPTEXT", + paramType: "var", + required: true, + }, + RFCTABLE: { + PARAMCLASS: "T", + PARAMTEXT: "Importing/exporting table", + TABNAME: "RFCTEST", + functionName: "STFC_STRUCTURE", + paramName: "RFCTABLE", + paramType: "table", + required: true, + }, + }, + }, + stat: { + STFC_CONNECTION: { exception: 0, struct: 0, table: 0, var: 3 }, + STFC_STRUCTURE: { exception: 0, struct: 2, table: 1, var: 1 }, + }, + usage: { RFCTEST: ["STFC_STRUCTURE"] }, + }, + frontend: { + STFC_CONNECTION: { + js: + "//\n" + + "// STFC_CONNECTION var: 3 struct: 0 table: 0 exception: 0\n" + + "//\n" + + "// abap api\n" + + "//\n" + + "\n" + + "// prettier-ignore\n" + + "const parameters = {\n" + + "\n" + + "// IMPORT PARAMETERS\n" + + "\n" + + 'REQUTEXT : "", // CHAR (255) no text (en)\n' + + "\n" + + "// EXPORT PARAMETERS\n" + + "\n" + + '// ECHOTEXT : "", // CHAR (255) no text (en)\n' + + '// RESPTEXT : "", // CHAR (255) no text (en)\n' + + "};\n" + + "\n" + + 'const result = await client.call("STFC_CONNECTION", parameters);\n' + + "\n" + + "//\n" + + "// IMPORT PARAMETERS\n" + + "//\n" + + "\n" + + "\n" + + "//\n" + + "// EXPORT PARAMETERS\n" + + "//\n", + }, + STFC_STRUCTURE: { + js: + "//\n" + + "// STFC_STRUCTURE var: 1 struct: 2 table: 1 exception: 0\n" + + "//\n" + + "// abap api\n" + + "//\n" + + "\n" + + "// prettier-ignore\n" + + "const parameters = {\n" + + "\n" + + "// IMPORT PARAMETERS\n" + + "\n" + + "IMPORTSTRUCT : {}, // RFCTEST Importing structure\n" + + "\n" + + "// TABLE PARAMETERS\n" + + "\n" + + "RFCTABLE : [], // RFCTEST Importing/exporting table\n" + + "\n" + + "// EXPORT PARAMETERS\n" + + "\n" + + '// RESPTEXT : "", // CHAR (255) Exporting response message\n' + + "// ECHOSTRUCT : {}, // RFCTEST Exporting structure\n" + + "};\n" + + "\n" + + 'const result = await client.call("STFC_STRUCTURE", parameters);\n' + + "\n" + + "//\n" + + "// IMPORT PARAMETERS\n" + + "//\n" + + "\n" + + "// RFCTEST Importing structure\n" + + "\n" + + "// prettier-ignore\n" + + "const IMPORTSTRUCT= {\n" + + ' RFCFLOAT : "0.0", // FLTP (16.16) Float field\n' + + ' RFCCHAR1 : "", // CHAR (1) Character field of length 1\n' + + " RFCINT2 : 0, // INT2 (5) INT2 field\n" + + " RFCINT1 : 0, // INT1 (3) INT1 field\n" + + ' RFCCHAR4 : "", // CHAR (4) Character field of length 4\n' + + " RFCINT4 : 0, // INT4 (10) INT4 field\n" + + " RFCHEX3 : bytes(), // RAW (3) HEX field of length 3\n" + + ' RFCCHAR2 : "", // CHAR (2) Character field of length 2\n' + + ' RFCTIME : "", // TIMS (6) Validity Period\n' + + ' RFCDATE : "", // DATS (8) Date field\n' + + ' RFCDATA1 : "", // CHAR (50) Comment\n' + + ' RFCDATA2 : "", // CHAR (50) Comment\n' + + "};\n" + + "\n" + + "\n" + + "//\n" + + "// TABLE PARAMETERS\n" + + "//\n" + + "\n" + + "// RFCTEST Importing/exporting table\n" + + "const RFCTABLE= [];\n" + + "\n" + + "// prettier-ignore\n" + + "const RFCTABLE= {\n" + + ' RFCFLOAT : "0.0", // FLTP (16.16) Float field\n' + + ' RFCCHAR1 : "", // CHAR (1) Character field of length 1\n' + + " RFCINT2 : 0, // INT2 (5) INT2 field\n" + + " RFCINT1 : 0, // INT1 (3) INT1 field\n" + + ' RFCCHAR4 : "", // CHAR (4) Character field of length 4\n' + + " RFCINT4 : 0, // INT4 (10) INT4 field\n" + + " RFCHEX3 : bytes(), // RAW (3) HEX field of length 3\n" + + ' RFCCHAR2 : "", // CHAR (2) Character field of length 2\n' + + ' RFCTIME : "", // TIMS (6) Validity Period\n' + + ' RFCDATE : "", // DATS (8) Date field\n' + + ' RFCDATA1 : "", // CHAR (50) Comment\n' + + ' RFCDATA2 : "", // CHAR (50) Comment\n' + + "};\n" + + "\n" + + "\n" + + "//\n" + + "// EXPORT PARAMETERS\n" + + "//\n" + + "\n" + + "// RFCTEST Exporting structure\n" + + "\n" + + "// prettier-ignore\n" + + "const ECHOSTRUCT= {\n" + + ' RFCFLOAT : "0.0", // FLTP (16.16) Float field\n' + + ' RFCCHAR1 : "", // CHAR (1) Character field of length 1\n' + + " RFCINT2 : 0, // INT2 (5) INT2 field\n" + + " RFCINT1 : 0, // INT1 (3) INT1 field\n" + + ' RFCCHAR4 : "", // CHAR (4) Character field of length 4\n' + + " RFCINT4 : 0, // INT4 (10) INT4 field\n" + + " RFCHEX3 : bytes(), // RAW (3) HEX field of length 3\n" + + ' RFCCHAR2 : "", // CHAR (2) Character field of length 2\n' + + ' RFCTIME : "", // TIMS (6) Validity Period\n' + + ' RFCDATE : "", // DATS (8) Date field\n' + + ' RFCDATA1 : "", // CHAR (50) Comment\n' + + ' RFCDATA2 : "", // CHAR (50) Comment\n' + + "};\n", + }, + }, + }; + + test("api: single rfm, destination", async () => { + expect.assertions(2); + const result = await api.get("MME", "stfc_connection"); + + expect(result.annotations).toMatchObject(RESULT1.annotations); + expect(result.frontend).toMatchObject(RESULT1.frontend); + }); + + test("api: single rfm, connection parameters", async () => { + expect.assertions(2); + const result = await api.get(cp, "stfc_connection"); + + expect(result.annotations).toMatchObject(RESULT1.annotations); + expect(result.frontend).toMatchObject(RESULT1.frontend); + }); + + test("api: array rfm, destination", async () => { + expect.assertions(2); + const result = await api.get("MME", ["stfc_connection", "stfc_structure"]); + + expect(result.annotations).toMatchObject(RESULT2.annotations); + expect(result.frontend).toMatchObject(RESULT2.frontend); + }); +}); diff --git a/doc/app.md b/doc/app.md index 1510a10a..d58d2cdf 100644 --- a/doc/app.md +++ b/doc/app.md @@ -2,7 +2,7 @@ Pattern based apps solve complex problems by re-usable patterns, rather than using complex frameworks. -The design is very low-code, by factors less than anything similar, without frameworks in between you and your application. What remains are problem-solving code-patterns and basic programming skills, you can start with. First applying patterns of others, then modifying them and finally building your own. With some knowledge of ABAP, or JavaScript or both. ABAP developers describe the approach as *ABAP driven*, Web developers as *Web driven*, in other words easy to try, no matter of background. +Without frameworks in between you and your application, what remains are code-patterns with by factors less code and basic programming skills, you can start with. First applying patterns of others, then modifying them and finally building your own. With some knowledge of ABAP, or JavaScript or both, it is easy to try, no matter of ABAP of Web development background. Apps comprise of four levels (JavaScript or JS stands for TypeScript or EcmaScript):