diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 50c9aabaf..9254fe1fd 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -4,11 +4,8 @@ - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) -- [ ] My code follows the code style of this project. -- [ ] My change requires a change to the documentation. - [ ] I have updated the documentation accordingly. - [ ] I have added tests to cover my changes. -- [ ] All new and existing tests passed. ### A description of the changes proposed in the Pull Request diff --git a/.github/workflows/release-commit.yml b/.github/workflows/release-commit.yml index 8ffa665f7..7172083c1 100644 --- a/.github/workflows/release-commit.yml +++ b/.github/workflows/release-commit.yml @@ -94,4 +94,4 @@ jobs: - name: Create pull request run: gh pr create -B ${{ vars.RELEASE_BRANCH_NAME }} -H $PR_BRANCH_NAME --title "Release ${{github.event.release.tag_name}}" --body "${{github.event.release.body}}" env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release-publish.yml b/.github/workflows/release-publish.yml index 3261fa840..a71a694aa 100644 --- a/.github/workflows/release-publish.yml +++ b/.github/workflows/release-publish.yml @@ -70,4 +70,4 @@ jobs: run: npm publish env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} \ No newline at end of file + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/manifests/examples/builtins/interpolation/success-with-off.yml b/manifests/examples/builtins/interpolation/success-with-off.yml new file mode 100644 index 000000000..0aebabbf4 --- /dev/null +++ b/manifests/examples/builtins/interpolation/success-with-off.yml @@ -0,0 +1,24 @@ +name: interpolation-demo +description: simple demo of interpolation plugin +tags: +initialize: + plugins: + interpolation: + method: Interpolation + path: "builtin" + config: + method: linear + x: [0, 10, 50, 100] + y: [0.12, 0.32, 0.75, 1.02] + input-parameter: "cpu/utilization" + output-parameter: "result" +tree: + children: + child: + pipeline: + compute: + - interpolation + inputs: + - timestamp: 2023-07-06T00:00 + duration: 3600 + cpu/utilization: off diff --git a/package-lock.json b/package-lock.json index 43766c712..551696574 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,17 +1,17 @@ { "name": "@grnsft/if", - "version": "0.7.0", + "version": "0.7.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@grnsft/if", - "version": "0.7.0", + "version": "0.7.2", "license": "MIT", "dependencies": { "@commitlint/cli": "^18.6.0", "@commitlint/config-conventional": "^18.6.0", - "@grnsft/if-core": "^0.0.25", + "@grnsft/if-core": "^0.0.28", "axios": "^1.7.2", "csv-parse": "^5.5.6", "csv-stringify": "^6.4.6", @@ -1186,9 +1186,9 @@ } }, "node_modules/@grnsft/if-core": { - "version": "0.0.25", - "resolved": "https://registry.npmjs.org/@grnsft/if-core/-/if-core-0.0.25.tgz", - "integrity": "sha512-1W4SXsXhXos06q4SBPc8QpgQPDhHEc03njrGcd/X2UiJyh0ycBKTqGCjuRPRipEayGgUxO0DwRNOgNcgzzcDkA==", + "version": "0.0.28", + "resolved": "https://registry.npmjs.org/@grnsft/if-core/-/if-core-0.0.28.tgz", + "integrity": "sha512-DM88HFeBbR1yl3bU0vFRgy6FnmUiyP4KhmtXp7HK1tMQHtnuKxzdPSxbfdpHsnUuHlvgDG7R/dI67/PmQD4U5w==", "dependencies": { "typescript": "^5.1.6", "zod": "^3.23.8" @@ -2703,9 +2703,9 @@ } }, "node_modules/axios": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", - "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", + "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -3329,9 +3329,9 @@ } }, "node_modules/cli-truncate/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, "engines": { "node": ">=12" @@ -3341,15 +3341,15 @@ } }, "node_modules/cli-truncate/node_modules/emoji-regex": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", - "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", "dev": true }, "node_modules/cli-truncate/node_modules/string-width": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", - "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, "dependencies": { "emoji-regex": "^10.3.0", @@ -3583,12 +3583,12 @@ } }, "node_modules/commander": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", - "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", "dev": true, "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/compare-func": { @@ -3913,11 +3913,12 @@ } }, "node_modules/debug": { - "version": "4.3.4", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dev": true, - "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -4338,6 +4339,18 @@ "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/error-ex": { "version": "1.3.2", "license": "MIT", @@ -5248,6 +5261,20 @@ "dev": true, "license": "ISC" }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", "license": "MIT", @@ -7864,12 +7891,15 @@ } }, "node_modules/lilconfig": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.0.0.tgz", - "integrity": "sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", + "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", "dev": true, "engines": { "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" } }, "node_modules/lines-and-columns": { @@ -7877,21 +7907,21 @@ "license": "MIT" }, "node_modules/lint-staged": { - "version": "15.2.2", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.2.tgz", - "integrity": "sha512-TiTt93OPh1OZOsb5B7k96A/ATl2AjIZo+vnzFZ6oHK5FuTk63ByDtxGQpHm+kFETjEWqgkF95M8FRXKR/LEBcw==", - "dev": true, - "dependencies": { - "chalk": "5.3.0", - "commander": "11.1.0", - "debug": "4.3.4", - "execa": "8.0.1", - "lilconfig": "3.0.0", - "listr2": "8.0.1", - "micromatch": "4.0.5", - "pidtree": "0.6.0", - "string-argv": "0.3.2", - "yaml": "2.3.4" + "version": "15.2.10", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.10.tgz", + "integrity": "sha512-5dY5t743e1byO19P9I4b3x8HJwalIznL5E1FWYnU6OWw33KxNBSLAc6Cy7F2PsFEO8FKnLwjwm5hx7aMF0jzZg==", + "dev": true, + "dependencies": { + "chalk": "~5.3.0", + "commander": "~12.1.0", + "debug": "~4.3.6", + "execa": "~8.0.1", + "lilconfig": "~3.1.2", + "listr2": "~8.2.4", + "micromatch": "~4.0.8", + "pidtree": "~0.6.0", + "string-argv": "~0.3.2", + "yaml": "~2.5.0" }, "bin": { "lint-staged": "bin/lint-staged.js" @@ -8050,16 +8080,16 @@ } }, "node_modules/listr2": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.0.1.tgz", - "integrity": "sha512-ovJXBXkKGfq+CwmKTjluEqFi3p4h8xvkxGQQAQan22YCgef4KZ1mKGjzfGh6PL6AW5Csw0QiQPNuQyH+6Xk3hA==", + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.5.tgz", + "integrity": "sha512-iyAZCeyD+c1gPyE9qpFu8af0Y+MRtmKOncdGoA2S5EY8iFq99dmmvkNnHiWo+pj0s7yH7l3KPIgee77tKpXPWQ==", "dev": true, "dependencies": { "cli-truncate": "^4.0.0", "colorette": "^2.0.20", "eventemitter3": "^5.0.1", - "log-update": "^6.0.0", - "rfdc": "^1.3.0", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", "wrap-ansi": "^9.0.0" }, "engines": { @@ -8067,9 +8097,9 @@ } }, "node_modules/listr2/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, "engines": { "node": ">=12" @@ -8091,15 +8121,15 @@ } }, "node_modules/listr2/node_modules/emoji-regex": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", - "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", "dev": true }, "node_modules/listr2/node_modules/string-width": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", - "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, "dependencies": { "emoji-regex": "^10.3.0", @@ -8266,14 +8296,14 @@ } }, "node_modules/log-update": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.0.0.tgz", - "integrity": "sha512-niTvB4gqvtof056rRIrTZvjNYE4rCUzO6X/X+kYjd7WFxXeJ0NwEFnRxX6ehkvv3jTwrXnNdtAak5XYZuIyPFw==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", "dev": true, "dependencies": { - "ansi-escapes": "^6.2.0", - "cli-cursor": "^4.0.0", - "slice-ansi": "^7.0.0", + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", "strip-ansi": "^7.1.0", "wrap-ansi": "^9.0.0" }, @@ -8285,21 +8315,24 @@ } }, "node_modules/log-update/node_modules/ansi-escapes": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.1.tgz", - "integrity": "sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz", + "integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==", "dev": true, + "dependencies": { + "environment": "^1.0.0" + }, "engines": { - "node": ">=14.16" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/log-update/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, "engines": { "node": ">=12" @@ -8321,24 +8354,24 @@ } }, "node_modules/log-update/node_modules/cli-cursor": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", - "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", "dev": true, "dependencies": { - "restore-cursor": "^4.0.0" + "restore-cursor": "^5.0.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/log-update/node_modules/emoji-regex": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", - "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", "dev": true }, "node_modules/log-update/node_modules/is-fullwidth-code-point": { @@ -8356,22 +8389,49 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/log-update/node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/log-update/node_modules/restore-cursor": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", - "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", "dev": true, "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/log-update/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/log-update/node_modules/slice-ansi": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz", @@ -8389,9 +8449,9 @@ } }, "node_modules/log-update/node_modules/string-width": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", - "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, "dependencies": { "emoji-regex": "^10.3.0", @@ -8586,11 +8646,12 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, - "license": "MIT", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -8623,6 +8684,18 @@ "node": ">=6" } }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/mimic-response": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", @@ -8682,8 +8755,9 @@ } }, "node_modules/ms": { - "version": "2.1.2", - "license": "MIT" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/mute-stream": { "version": "0.0.8", @@ -10305,9 +10379,9 @@ } }, "node_modules/rfdc": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.1.tgz", - "integrity": "sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", "dev": true }, "node_modules/rimraf": { @@ -11830,10 +11904,13 @@ "license": "ISC" }, "node_modules/yaml": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", - "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.1.tgz", + "integrity": "sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==", "dev": true, + "bin": { + "yaml": "bin.mjs" + }, "engines": { "node": ">= 14" } diff --git a/package.json b/package.json index 6aaed3cf1..c0d92fffc 100644 --- a/package.json +++ b/package.json @@ -1,18 +1,18 @@ { "name": "@grnsft/if", "description": "Impact Framework", - "version": "0.7.0", + "version": "0.7.2", "author": { "name": "Green Software Foundation", "email": "info@gsf.com" }, "bin": { - "if-diff": "./build/if-diff/index.js", - "if-run": "./build/if-run/index.js", - "if-env": "./build/if-env/index.js", - "if-check": "./build/if-check/index.js", - "if-csv": "./build/if-csv/index.js", - "if-merge": "./build/if-merge/index.js" + "if-diff": "build/if-diff/index.js", + "if-run": "build/if-run/index.js", + "if-env": "build/if-env/index.js", + "if-check": "build/if-check/index.js", + "if-csv": "build/if-csv/index.js", + "if-merge": "build/if-merge/index.js" }, "bugs": { "url": "https://github.com/Green-Software-Foundation/if/issues/new?assignees=&labels=feedback&projects=&template=feedback.md&title=Feedback+-+" @@ -20,7 +20,7 @@ "dependencies": { "@commitlint/cli": "^18.6.0", "@commitlint/config-conventional": "^18.6.0", - "@grnsft/if-core": "^0.0.25", + "@grnsft/if-core": "^0.0.28", "axios": "^1.7.2", "csv-parse": "^5.5.6", "csv-stringify": "^6.4.6", @@ -70,7 +70,7 @@ "access": "public" }, "repository": { - "url": "https://github.com/Green-Software-Foundation/if" + "url": "git+https://github.com/Green-Software-Foundation/if.git" }, "scripts": { "build": "npm run clean && tsc --project tsconfig.build.json", @@ -87,6 +87,7 @@ "lint": "gts lint", "pre-commit": "lint-staged", "prepare": "husky install", + "prepublishOnly": "npm run build", "release": "release-it", "test": "jest --verbose --testPathPattern=src/__tests__/" }, diff --git a/src/__tests__/if-run/builtins/interpolation.test.ts b/src/__tests__/if-run/builtins/interpolation.test.ts index be379b3d3..dd5381529 100644 --- a/src/__tests__/if-run/builtins/interpolation.test.ts +++ b/src/__tests__/if-run/builtins/interpolation.test.ts @@ -55,6 +55,50 @@ describe('builtins/interpolation: ', () => { expect(result).toEqual(outputs); }); + it('returns valid output parameter if input parameter is 0.', async () => { + const inputs = [ + { + timestamp: '2023-07-06T00:00', + duration: 3600, + 'cpu/utilization': 0, + }, + ]; + const outputs = [ + { + timestamp: '2023-07-06T00:00', + duration: 3600, + 'cpu/utilization': 0, + 'interpolation-result': 0.12, + }, + ]; + + const result = await plugin.execute(inputs); + + expect(result).toEqual(outputs); + }); + + it('returns no output parameter if input parameter is `off`.', async () => { + const inputs = [ + { + timestamp: '2023-07-06T00:00', + duration: 3600, + 'cpu/utilization': 'off', + }, + ]; + const outputs = [ + { + timestamp: '2023-07-06T00:00', + duration: 3600, + 'cpu/utilization': 0, + 'interpolation-result': 0, + }, + ]; + + const result = await plugin.execute(inputs); + + expect(result).toEqual(outputs); + }); + it('returns result when `mapping` has valid data.', async () => { const mapping = { 'cpu/utilization': 'cpu/util', diff --git a/src/__tests__/if-run/lib/explain.test.ts b/src/__tests__/if-run/lib/explain.test.ts index df86448ac..a6049f500 100644 --- a/src/__tests__/if-run/lib/explain.test.ts +++ b/src/__tests__/if-run/lib/explain.test.ts @@ -13,10 +13,6 @@ describe('lib/explain: ', () => { const mockData = { pluginName: 'divide', metadata: {kind: 'execute', inputs: undefined, outputs: undefined}, - pluginData: { - path: 'builtin', - method: 'Divide', - }, }; addExplainData(mockData); @@ -50,30 +46,29 @@ describe('lib/explain: ', () => { }, }, }, - pluginData: { - path: 'builtin', - method: 'Sum', - }, }; const expectedResult = { - 'cpu/energy': { - plugins: ['sum'], - unit: 'kWh', - description: 'energy consumed by the cpu', - 'aggregation-method': 'sum', - }, - 'network/energy': { - plugins: ['sum'], - unit: 'kWh', - description: 'energy consumed by data ingress and egress', - 'aggregation-method': 'sum', - }, - 'energy-sum': { - plugins: ['sum'], - unit: 'kWh', - description: 'sum of energy components', - 'aggregation-method': 'sum', + sum: { + inputs: { + 'cpu/energy': { + unit: 'kWh', + description: 'energy consumed by the cpu', + 'aggregation-method': 'sum', + }, + 'network/energy': { + unit: 'kWh', + description: 'energy consumed by data ingress and egress', + 'aggregation-method': 'sum', + }, + }, + outputs: { + 'energy-sum': { + unit: 'kWh', + description: 'sum of energy components', + 'aggregation-method': 'sum', + }, + }, }, }; @@ -111,42 +106,50 @@ describe('lib/explain: ', () => { }, }, }, - pluginData: { - path: 'builtin', - method: 'Sum', - }, }; const expectedResult = { - 'cpu/energy': { - plugins: ['sum', 'sum-energy'], - unit: 'kWh', - description: 'energy consumed by the cpu', - 'aggregation-method': 'sum', - }, - 'network/energy': { - plugins: ['sum'], - unit: 'kWh', - description: 'energy consumed by data ingress and egress', - 'aggregation-method': 'sum', - }, - 'energy-sum': { - plugins: ['sum'], - unit: 'kWh', - description: 'sum of energy components', - 'aggregation-method': 'sum', - }, - 'memory/energy': { - plugins: ['sum-energy'], - unit: 'kWh', - description: 'energy consumed by data from memory', - 'aggregation-method': 'sum', + sum: { + inputs: { + 'cpu/energy': { + unit: 'kWh', + description: 'energy consumed by the cpu', + 'aggregation-method': 'sum', + }, + 'network/energy': { + unit: 'kWh', + description: 'energy consumed by data ingress and egress', + 'aggregation-method': 'sum', + }, + }, + outputs: { + 'energy-sum': { + unit: 'kWh', + description: 'sum of energy components', + 'aggregation-method': 'sum', + }, + }, }, - 'total/energy': { - plugins: ['sum-energy'], - unit: 'kWh', - description: 'sum of energy components', - 'aggregation-method': 'sum', + 'sum-energy': { + inputs: { + 'cpu/energy': { + unit: 'kWh', + description: 'energy consumed by the cpu', + 'aggregation-method': 'sum', + }, + 'memory/energy': { + unit: 'kWh', + description: 'energy consumed by data from memory', + 'aggregation-method': 'sum', + }, + }, + outputs: { + 'total/energy': { + unit: 'kWh', + description: 'sum of energy components', + 'aggregation-method': 'sum', + }, + }, }, }; @@ -184,10 +187,6 @@ describe('lib/explain: ', () => { }, }, }, - pluginData: { - path: 'builtin', - method: 'Sum', - }, }; expect.assertions(2); @@ -239,10 +238,6 @@ describe('lib/explain: ', () => { }, }, }, - pluginData: { - path: 'builtin', - method: 'Sum', - }, }; expect.assertions(2); diff --git a/src/common/config/strings.ts b/src/common/config/strings.ts index e5884852b..62cb0baa2 100644 --- a/src/common/config/strings.ts +++ b/src/common/config/strings.ts @@ -11,7 +11,11 @@ Incubation projects are experimental, offer no support guarantee, have minimal g MANIFEST_IS_MISSING: 'Manifest is missing.', DIRECTORY_NOT_FOUND: 'Directory not found.', AGGREGATION_UNITS_NOT_MATCH: (param: string) => - `Your manifest uses two instances of ${param} with different units. Please check that you are using consistent units for ${param} throughout your manifest.`, + `Your manifest uses two instances of \`${param}\` with different units. Please check that you are using consistent units for \`${param}\` throughout your manifest.`, AGGREGATION_METHODS_NOT_MATCH: (param: string) => - `Your manifest uses two instances of ${param} with different 'aggregation-method'. Please check that you are using right 'aggregation-method' for ${param} throughout your manifest.`, + `Your manifest uses two instances of \`${param}\` with different 'aggregation-method'. Please check that you are using right 'aggregation-method' for \`${param}\` throughout your manifest.`, + MISSING_INPUTS_PARAMETER: (pluginName: string) => + `The inputs parameter metadata of the \`${pluginName}\` plugin is missing.`, + MISSING_OUTPUTS_PARAMETER: (pluginName: string) => + `The outputs parameter metadata of the \`${pluginName}\` plugin is missing.`, }; diff --git a/src/if-run/builtins/interpolation/README.md b/src/if-run/builtins/interpolation/README.md index d328dc9aa..9b62e7000 100644 --- a/src/if-run/builtins/interpolation/README.md +++ b/src/if-run/builtins/interpolation/README.md @@ -62,7 +62,7 @@ The plugin expects the following input parameters: - `timestamp`: a timestamp for the input (required) - `duration`: the amount of time, in seconds, that the input covers. (required) -- `[input-parameter]` - a field whose name matches the string provided to input-parameter in config (i.e. if the input-parameter in config is cpu/utilisation then cpu-utilisation must exist in the input data) +- `[input-parameter]` - a field whose name matches the string provided to input-parameter in config (i.e. if the input-parameter in config is cpu/utilisation then cpu-utilisation must exist in the input data). Value can be greater or equal to 0. For modeling server which totally turned off, `off` value can be used. ## Output diff --git a/src/if-run/builtins/interpolation/index.ts b/src/if-run/builtins/interpolation/index.ts index 30226e5a6..bfc39e3c8 100644 --- a/src/if-run/builtins/interpolation/index.ts +++ b/src/if-run/builtins/interpolation/index.ts @@ -54,12 +54,13 @@ export const Interpolation = PluginFactory({ .object({ timestamp: z.string().or(z.date()), duration: z.number(), - [inputParameter]: z.number().gt(0), + [inputParameter]: z.number().gte(0).or(z.literal('off')), }) .refine( data => - data[inputParameter] >= config.x[0] && - data[inputParameter] <= config.x[config.x.length - 1], + (data[inputParameter] >= config.x[0] && + data[inputParameter] <= config.x[config.x.length - 1]) || + data[inputParameter] === 'off', { message: WITHIN_THE_RANGE, } @@ -68,14 +69,23 @@ export const Interpolation = PluginFactory({ return validate>(schema, input, index); }, implementation: async (inputs: PluginParams[], config: ConfigParams) => { - const {'output-parameter': outputParameter} = config; + const { + 'input-parameter': inputParameter, + 'output-parameter': outputParameter, + } = config; return inputs.map(input => { - const calculatedResult = calculateResult(config, input); + if (input[inputParameter] === 'off') { + return { + ...input, + [inputParameter]: 0, + [outputParameter]: 0, + }; + } return { ...input, - [outputParameter]: calculatedResult, + [outputParameter]: calculateResult(config, input), }; }); }, @@ -169,7 +179,8 @@ const getPolynomialInterpolation = ( return result; }; +/** + * Sorts given point items in ascending order. + */ const sortPoints = (items: number[]) => - items.sort((a: number, b: number) => { - return a - b; - }); + items.sort((a: number, b: number) => a - b); diff --git a/src/if-run/lib/compute.ts b/src/if-run/lib/compute.ts index 5e73cbbb4..0381fee10 100644 --- a/src/if-run/lib/compute.ts +++ b/src/if-run/lib/compute.ts @@ -99,8 +99,8 @@ const computeNode = async (node: Node, params: ComputeParams): Promise => { }); } - let inputStorage = structuredClone(node.inputs) as PluginParams[]; - inputStorage = mergeDefaults(inputStorage, defaults); + let outputStorage = structuredClone(node.inputs) as PluginParams[]; + outputStorage = mergeDefaults(outputStorage, defaults); const pipelineCopy = structuredClone(pipeline) || {}; /** Checks if pipeline is not an array or empty object. */ @@ -125,14 +125,13 @@ const computeNode = async (node: Node, params: ComputeParams): Promise => { const plugin = params.pluginStorage.get(pluginName); const nodeConfig = config && config[pluginName]; - inputStorage = await plugin.execute(inputStorage, nodeConfig); - node.inputs = inputStorage; + outputStorage = await plugin.execute(outputStorage, nodeConfig); + node.inputs = outputStorage; if (params.context.explainer) { addExplainData({ pluginName, metadata: plugin.metadata, - pluginData: params.context.initialize!.plugins[pluginName], }); } } @@ -145,7 +144,7 @@ const computeNode = async (node: Node, params: ComputeParams): Promise => { const originalOutputs = params.append ? node.outputs || [] : []; node.children = Regroup( - inputStorage, + outputStorage, originalOutputs, pipelineCopy.regroup ); @@ -183,16 +182,16 @@ const computeNode = async (node: Node, params: ComputeParams): Promise => { console.debug(COMPUTING_PIPELINE_FOR_NODE(pluginName)); debugLogger.setExecutingPluginName(pluginName); - inputStorage = await plugin.execute(inputStorage, nodeConfig); + outputStorage = await plugin.execute(outputStorage, nodeConfig); + debugLogger.setExecutingPluginName(); - node.outputs = inputStorage; + node.outputs = outputStorage; if (params.context.explainer) { addExplainData({ pluginName, metadata: plugin.metadata, - pluginData: params.context.initialize!.plugins[pluginName], }); } } diff --git a/src/if-run/lib/explain.ts b/src/if-run/lib/explain.ts index 470eed2e7..017d20f5d 100644 --- a/src/if-run/lib/explain.ts +++ b/src/if-run/lib/explain.ts @@ -1,82 +1,133 @@ +import {ParameterMetadata} from '@grnsft/if-core/types'; import {ERRORS} from '@grnsft/if-core/utils'; import {STRINGS} from '../../common/config'; +import {logger} from '../../common/util/logger'; + import {ExplainParams, ExplainStorageType} from '../types/explain'; const {ManifestValidationError} = ERRORS; -const {AGGREGATION_UNITS_NOT_MATCH, AGGREGATION_METHODS_NOT_MATCH} = STRINGS; +const { + AGGREGATION_UNITS_NOT_MATCH, + AGGREGATION_METHODS_NOT_MATCH, + MISSING_INPUTS_PARAMETER, + MISSING_OUTPUTS_PARAMETER, +} = STRINGS; /** * Retrieves stored explain data. */ -export const explain = () => storeExplainData.parameters; +export const explain = () => storeExplainData.plugins; /** * Manages the storage of explain data. */ const storeExplainData = (() => { - let parameter: ExplainStorageType = {}; + let plugins: ExplainStorageType = {}; - const parameterManager = { - get parameters() { - return parameter; + const pluginManager = { + get plugins() { + return plugins; }, - set parameters(value: ExplainStorageType) { - parameter = value; + set plugins(value: ExplainStorageType) { + plugins = value; }, }; - return parameterManager; + return pluginManager; })(); /** * Adds new explain data to the stored explain data. */ export const addExplainData = (params: ExplainParams) => { - const {pluginName, pluginData, metadata} = params; - const parameterMetadata = pluginData?.['parameter-metadata'] || metadata; - const parameters = storeExplainData.parameters; - const allParameters = { - ...parameterMetadata?.inputs, - ...parameterMetadata?.outputs, - } as ExplainStorageType; - - Object.entries(allParameters).forEach(([name, meta]) => { - const existingParameter = parameters[name]; - - if (parameters[name]?.plugins?.includes(pluginName)) { - return; - } + const {pluginName, metadata} = params; + const plugin: ExplainStorageType = { + [pluginName]: { + inputs: metadata?.inputs ?? {}, + outputs: metadata?.outputs ?? {}, + }, + }; - if (existingParameter) { - if (meta.unit !== existingParameter.unit) { - throw new ManifestValidationError(AGGREGATION_UNITS_NOT_MATCH(name)); - } + const isInputsMissing = !Object.keys(plugin[pluginName].inputs || {}).length; + const isOutputsMissing = !Object.keys(plugin[pluginName].outputs || {}) + .length; + + if (isInputsMissing) { + delete plugin[pluginName].inputs; + + logger.warn(MISSING_INPUTS_PARAMETER(pluginName)); + } + + if (isOutputsMissing) { + delete plugin[pluginName].outputs; + + logger.warn(MISSING_OUTPUTS_PARAMETER(pluginName)); + } + + checkMetadatas(metadata); + + if (!isInputsMissing || !isOutputsMissing) { + storeExplainData.plugins = { + ...storeExplainData.plugins, + ...plugin, + }; + } +}; - if ( - meta['aggregation-method'].component !== - existingParameter['aggregation-method'].component || - meta['aggregation-method'].time !== - existingParameter['aggregation-method'].time - ) { - throw new ManifestValidationError(AGGREGATION_METHODS_NOT_MATCH(name)); +/** + * Checks if the 'unit' and 'aggregation-method' of the parameter are the same throughout the manifest + */ +const checkMetadatas = (metadata: { + inputs?: ParameterMetadata; + outputs?: ParameterMetadata; +}) => { + const inputsOutputsMetadata = {...metadata?.inputs, ...metadata?.outputs}; + const storedParameters: any = {}; + + // Populate stored parameters with metadata from each plugin + Object.values(storeExplainData.plugins).forEach(plugin => { + const storedInputOutputMetadata = {...plugin.inputs, ...plugin.outputs}; + + Object.keys(storedInputOutputMetadata).forEach(parameter => { + if (!storedParameters[parameter]) { + storedParameters[parameter] = { + unit: storedInputOutputMetadata[parameter].unit, + 'aggregation-method': + storedInputOutputMetadata[parameter]['aggregation-method'], + }; } + }); + }); + + // Validate input-output metadata against stored parameters + Object.keys(inputsOutputsMetadata).forEach(parameterName => { + const parameter = inputsOutputsMetadata[parameterName]; + const storedParameter = storedParameters[parameterName]; - existingParameter.plugins.push(pluginName); - existingParameter.description = - meta.description || existingParameter.description; - } else { - parameters[name] = { - plugins: [pluginName], - unit: meta.unit, - description: meta.description, - 'aggregation-method': meta['aggregation-method'], - }; + if ( + parameter && + Object.keys(storedParameters).includes(parameterName) && + storedParameter.unit !== parameter.unit + ) { + throw new ManifestValidationError( + AGGREGATION_UNITS_NOT_MATCH(parameterName) + ); } - }); - storeExplainData.parameters = { - ...parameters, - }; + // Check for aggregation-method mismatch + const inputAggregation = parameter['aggregation-method']; + + if ( + storedParameter && + (storedParameter['aggregation-method']?.component !== + inputAggregation?.component || + storedParameter['aggregation-method']?.time !== inputAggregation?.time) + ) { + throw new ManifestValidationError( + AGGREGATION_METHODS_NOT_MATCH(parameterName) + ); + } + }); }; diff --git a/src/if-run/lib/initialize.ts b/src/if-run/lib/initialize.ts index 554b4f9c0..5ae3787f1 100644 --- a/src/if-run/lib/initialize.ts +++ b/src/if-run/lib/initialize.ts @@ -3,6 +3,8 @@ import * as path from 'node:path'; import {ERRORS} from '@grnsft/if-core/utils'; import {PluginInterface} from '@grnsft/if-core/types'; +import {storeAggregationMetrics} from './aggregate'; + import {logger} from '../../common/util/logger'; import {memoizedLog} from '../util/log-memoize'; import {pluginStorage} from '../util/plugin-storage'; @@ -11,7 +13,6 @@ import {CONFIG, STRINGS} from '../config'; import {Context, PluginOptions} from '../../common/types/manifest'; import {PluginStorageInterface} from '../types/plugin-storage'; -import {storeAggregationMetrics} from './aggregate'; const { PluginInitializationError, diff --git a/src/if-run/lib/regroup.ts b/src/if-run/lib/regroup.ts index 7e39b1c89..55d8f8221 100644 --- a/src/if-run/lib/regroup.ts +++ b/src/if-run/lib/regroup.ts @@ -7,93 +7,82 @@ import {validate} from '../../common/util/validations'; import {STRINGS} from '../config'; const {InvalidGroupingError} = ERRORS; - const {INVALID_GROUP_KEY, REGROUP_ERROR} = STRINGS; /** - * Grouping strategy. + * Creates structure to insert inputs by groups. */ -export const Regroup = ( - inputs: PluginParams[], - outputs: PluginParams[], +const appendGroup = ( + value: PluginParams, + object: any, + target: string, groups: string[] -) => { - /** - * Creates structure to insert inputs by groups. - */ - const appendGroup = ( - value: PluginParams, - object: any, - target: string, - groups: string[] - ) => { - if (groups.length > 0) { - const group = groups.shift() as string; - - object.children = object.children ?? {}; - object.children[group] = object.children[group] ?? {}; +): any => { + if (groups.length === 0) { + object[target] = object[target] || []; + object[target].push(value); + return object; + } - if (groups.length === 0) { - if ( - object.children[group][target] && - object.children[group][target].length > 0 - ) { - object.children[group][target].push(value); - } else { - object.children[group][target] = [value]; - } - } + const group = groups.shift()!; + object.children = object.children || {}; + object.children[group] = object.children[group] || {}; - appendGroup(value, object.children[group], target, groups); - } + return appendGroup(value, object.children[group], target, groups); +}; - return object; - }; +/** + * Validates the groups array. + */ +const validateGroups = (groups: string[]): string[] => { + const inputData = {regroup: groups}; + const validationSchema = z.record( + z.string(), + z.array(z.string(), {message: REGROUP_ERROR}).min(1) + ); - /** - * Validates groups array. - */ - const validateGroups = (regroup: string[]) => { - const inputData = {regroup}; - const validationSchema = z.record( - z.string(), - z.array(z.string(), {message: REGROUP_ERROR}).min(1) - ); + validate(validationSchema, inputData); - validate(validationSchema, inputData); + return groups; +}; - return groups; - }; +/** + * Looks up a group key value in the input. + */ +const lookupGroupKey = (input: PluginParams, groupKey: string): string => { + if (!input[groupKey]) { + throw new InvalidGroupingError(INVALID_GROUP_KEY(groupKey)); + } - /** - * Interates over inputs, grabs group values for each one. - * Based on grouping, initializes the structure. - */ + return input[groupKey]; +}; +/** + * Regroups inputs and outputs based on the given group keys. + */ +export const Regroup = ( + inputs: PluginParams[], + outputs: PluginParams[], + groups: string[] +): any => { const validatedGroups = validateGroups(groups); - const lookupGroupKey = (input: PluginParams, groupKey: string) => { - if (!input[groupKey]) { - throw new InvalidGroupingError(INVALID_GROUP_KEY(groupKey)); + const appendToAccumulator = ( + items: PluginParams[], + acc: any, + target: string + ) => { + for (const item of items) { + const groupsWithData = validatedGroups.map(groupKey => + lookupGroupKey(item, groupKey) + ); + appendGroup(item, acc, target, groupsWithData); } - - return input[groupKey]; }; - let acc = {} as any; - for (const input of inputs) { - const groupsWithData = validatedGroups.map(groupKey => - lookupGroupKey(input, groupKey) - ); - acc = appendGroup(input, acc, 'inputs', groupsWithData); - } - - for (const output of outputs) { - const groupsWithData = validatedGroups.map(groupKey => - lookupGroupKey(output, groupKey) - ); - acc = appendGroup(output, acc, 'outputs', groupsWithData); - } + const acc = {} as any; + appendToAccumulator(inputs, acc, 'inputs'); + appendToAccumulator(outputs, acc, 'outputs'); return acc.children; }; diff --git a/src/if-run/types/explain.ts b/src/if-run/types/explain.ts index caedd3992..8fc51ac10 100644 --- a/src/if-run/types/explain.ts +++ b/src/if-run/types/explain.ts @@ -1,19 +1,14 @@ -import {AggregationOptions, ParameterMetadata} from '@grnsft/if-core/types'; - -import {PluginOptions} from '../../common/types/manifest'; +import {ParameterMetadata} from '@grnsft/if-core/types'; export type ExplainParams = { pluginName: string; - pluginData: PluginOptions; metadata: {inputs?: ParameterMetadata; outputs?: ParameterMetadata}; }; export type ExplainStorageType = Record< string, { - plugins: string[]; - unit: string; - description: string; - 'aggregation-method': AggregationOptions; + inputs?: ParameterMetadata; + outputs?: ParameterMetadata; } >; diff --git a/src/if-run/util/aggregation-helper.ts b/src/if-run/util/aggregation-helper.ts index defa71726..6e9f4e071 100644 --- a/src/if-run/util/aggregation-helper.ts +++ b/src/if-run/util/aggregation-helper.ts @@ -39,12 +39,12 @@ export const aggregateOutputsIntoOne = ( const aggregationType = isTemporal ? 'component' : 'time'; if (aggregationParams[aggregationType] === 'none') { - return acc; + continue; } if (aggregationParams[aggregationType] === 'copy') { acc[metric] = output[metric]; - return acc; + continue; } acc[metric] = acc[metric] ?? 0;