From 7f0413d8d0bb573c5ac61de684109894d5149d2f Mon Sep 17 00:00:00 2001 From: Simon Kowallik Date: Fri, 23 Feb 2024 23:49:11 +0000 Subject: [PATCH] v1.1.0 --- .github/workflows/release-containers.yaml | 52 ++ Dockerfile | 9 + README.md | 172 +++++- SUPPORT.md | 4 +- example/demo.js | 15 + example/imap.tmconf | 3 + example/pop3.json | 5 + example/pop3.tmconf | 3 + example/test.tmconf.json | 2 +- package-lock.json | 711 +--------------------- package.json | 25 +- tmconfjs.js | 133 ++++ tmconfparse.js | 33 - vendored/README.md | 15 +- vendored/preConverter/extract.js | 60 -- vendored/preConverter/readFiles.js | 41 -- vendored/util/log.js | 108 ++-- 17 files changed, 441 insertions(+), 950 deletions(-) create mode 100644 .github/workflows/release-containers.yaml create mode 100644 Dockerfile create mode 100644 example/demo.js create mode 100644 example/imap.tmconf create mode 100644 example/pop3.json create mode 100644 example/pop3.tmconf create mode 100755 tmconfjs.js delete mode 100755 tmconfparse.js delete mode 100644 vendored/preConverter/extract.js delete mode 100644 vendored/preConverter/readFiles.js diff --git a/.github/workflows/release-containers.yaml b/.github/workflows/release-containers.yaml new file mode 100644 index 0000000..66484e2 --- /dev/null +++ b/.github/workflows/release-containers.yaml @@ -0,0 +1,52 @@ +name: Release Containers + +on: + workflow_dispatch: + release: + types: [released] + +jobs: + release: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push + uses: docker/build-push-action@v5 + with: + context: . + platforms: linux/amd64,linux/arm64/v8 + file: Dockerfile + push: true + cache-from: type=gha + cache-to: type=gha,mode=max + tags: | + simonkowallik/tmconfjs:latest + ghcr.io/simonkowallik/tmconfjs:latest + + - name: Docker Hub Description + uses: peter-evans/dockerhub-description@v4 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + # docker... https://github.com/peter-evans/dockerhub-description/issues/10 + password: ${{ secrets.DOCKERHUB_TOKEN }} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..1b18599 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,9 @@ +FROM node:lts-alpine + +WORKDIR /tmconfjs + +ADD . /tmconfjs + +RUN npm install --global /tmconfjs/ + +CMD ["tmconfjs"] diff --git a/README.md b/README.md index ee4eadf..9620bd9 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,23 @@ # tmconfjs -**tmconfjs** provides a simple parser (`tmconfparse` command) to serialize a tmconf file (eg. `/config/bigip.conf`) to JSON. The produced JSON is printed to `STDOUT`. +**tmconfjs** provides a simple parser (`tmconfjs` command) to serialize a tmconf file (eg. `/config/bigip.conf`) to JSON. The produced JSON is printed to `STDOUT` or a specified file. -This project is (supposed to be) a minimal wrapper and vendors the necessary code from the community project [F5 BIG-IP Automation Config Converter (BIG-IP ACC)](https://github.com/f5devcentral/f5-automation-config-converter/). +This project is a minimal wrapper and vendors the necessary code from the community project [F5 BIG-IP Automation Config Converter (BIG-IP ACC)](https://github.com/f5devcentral/f5-automation-config-converter/). -## Usage example +## Documentation by example + +### Installation ```shell -npm install -g https://github.com/simonkowallik/tmconfjs +npm install --global simonkowallik/tmconfjs ``` +### Command line usage + +When installed globally, `tmconfjs` can be invoked as a command: + ```shell -tmconfparse example/test.tmconf 2>/dev/null \ +tmconfjs example/test.tmconf 2>/dev/null \ | jq '."ltm profile client-ssl clientssl-secure"' ``` @@ -39,20 +45,160 @@ tmconfparse example/test.tmconf 2>/dev/null \ } ``` -Any errors or info is written to `STDERR`. +When this repo has been copied or cloned, invoke tmconfjs.js using node. An alternative is using npx, `npx tmconfjs` would work also. +Errors, warnings or any debug information is written to `STDERR`: + +```shell +node ./tmconfjs.js example/test.tmconf \ + >/dev/null 2> example/test.tmconf.log + +cat example/test.tmconf.log +``` + +```shell +2024-02-23T21:47:31.594Z WARN UNRECOGNIZED LINE: ' auto-check enabled' +2024-02-23T21:47:31.595Z WARN UNRECOGNIZED LINE: ' auto-phonehome enabled' +2024-02-23T21:47:31.602Z WARN UNRECOGNIZED LINE: ' time 500' +2024-02-23T21:47:31.602Z WARN UNRECOGNIZED LINE: ' enabled yes' +``` + +Input is also accepted from `STDIN`: + +```shell +cat example/imap.tmconf | node tmconfjs.js +``` + +```json +{ + "ltm profile imap imap": { + "activation-mode": "require" + } +} +``` + +The `` argument is preferred over `STDIN` however: + +```shell +cat example/imap.tmconf | node tmconfjs.js example/pop3.tmconf +``` + +```json +{ + "ltm profile pop3 pop3": { + "activation-mode": "require" + } +} +``` + +The output can be written to a specified file using `--output` or `-o` when `STDOUT` is not desired: + +```shell +node tmconfjs.js --output example/pop3.json example/pop3.tmconf +cat example/pop3.json +``` + +```json +{ + "ltm profile pop3 pop3": { + "activation-mode": "require" + } +} +``` + +More debug information is available and might help understand issues: + +```shell +export LOG_LEVEL=debug +cat example/imap.tmconf | node tmconfjs.js example/pop3.tmconf 2> debug.log +``` + +```json +{ + "ltm profile pop3 pop3": { + "activation-mode": "require" + } +} +``` + +```shell +cat debug.log +``` ```shell -# run node and tmconfparse.js as first argument followed by tmconfparse arguments. -node ./tmconfparse.js example/test.tmconf >/dev/null +2024-02-23T21:54:04.300Z DEBUG Parsing from : example/pop3.tmconf +2024-02-23T21:54:04.302Z DEBUG Parsing data ``` +### Container / Docker + +Note the docker run options, `--rm` deletes the container right after it was executed and ended, +`-i` run the container interactively (required for STDIN to work). Also note the absence of the common `-t` option, which indicates a TTY/terminal - STDIN would fail when this is used. + ```shell -2024-02-17 00:29:17 WARN UNRECOGNIZED LINE: ' auto-check enabled' -2024-02-17 00:29:17 WARN UNRECOGNIZED LINE: ' auto-phonehome enabled' -2024-02-17 00:29:17 WARN UNRECOGNIZED LINE: ' time 500' -2024-02-17 00:29:17 WARN UNRECOGNIZED LINE: ' enabled yes' +cat example/imap.tmconf | docker run --rm -i simonkowallik/tmconfjs +``` + +```json +{ + "ltm profile imap imap": { + "activation-mode": "require" + } +} +``` + +Using volumes is another option: + +```shell +docker run --rm -v $PWD/example:/data simonkowallik/tmconfjs \ + tmconfjs /data/pop3.tmconf -o /data/pop3.json + +cat example/pop3.json +``` + +```json +{ + "ltm profile pop3 pop3": { + "activation-mode": "require" + } +} +``` + +### Use as module + +A simple `demo.js` is available at [example/demo.js](./example/demo.js). + +Just require either `parse` or `parseFile`. Both take a string as input, `parse` expects tmconf within the string while `parseFile` expects a path to a tmconf file. + +```javascript +// demo.js +'use strict' + +// use parse function from tmconfjs.js +const parse = require('../tmconfjs.js').parse + +const tmconf = ` +ltm profile pop3 pop3 { + activation-mode require +}` + +// supply string with tmconf to parse function +const tmconfAsJSON = parse(tmconf) + +console.log(JSON.stringify(tmconfAsJSON, null, 4)) +``` + +```shell +node example/demo.js +``` + +```json +{ + "ltm profile pop3 pop3": { + "activation-mode": "require" + } +} ``` ## Disclaimer -Please read and understand the LICENSE as well as the provided SUPPORT.md. +Please read and understand the [LICENSE](./LICENSE) as well as the provided [SUPPORT.md](./SUPPORT.md). diff --git a/SUPPORT.md b/SUPPORT.md index 1c70fa8..0e9acf6 100644 --- a/SUPPORT.md +++ b/SUPPORT.md @@ -2,4 +2,6 @@ There is no support on this project. It is maintained on best effort basis without any warranties. Please read and understand the LICENSE first. -Any software or components used in this project have their own LICENSE and SUPPORT policies. \ No newline at end of file +For any software or components used in this project, read their own LICENSE and SUPPORT policies. + +If you decide to use this project, you are solely responsible. diff --git a/example/demo.js b/example/demo.js new file mode 100644 index 0000000..3ee23af --- /dev/null +++ b/example/demo.js @@ -0,0 +1,15 @@ +// demo.js +'use strict' + +// use parse function from tmconfjs.js +const parse = require('../tmconfjs.js').parse + +const tmconf = ` +ltm profile pop3 pop3 { + activation-mode require +}` + +// supply string with tmconf to parse function +const tmconfAsJSON = parse(tmconf) + +console.log(JSON.stringify(tmconfAsJSON, null, 4)) diff --git a/example/imap.tmconf b/example/imap.tmconf new file mode 100644 index 0000000..0d9522f --- /dev/null +++ b/example/imap.tmconf @@ -0,0 +1,3 @@ +ltm profile imap imap { + activation-mode require +} \ No newline at end of file diff --git a/example/pop3.json b/example/pop3.json new file mode 100644 index 0000000..b298b13 --- /dev/null +++ b/example/pop3.json @@ -0,0 +1,5 @@ +{ + "ltm profile pop3 pop3": { + "activation-mode": "require" + } +} \ No newline at end of file diff --git a/example/pop3.tmconf b/example/pop3.tmconf new file mode 100644 index 0000000..6e111c3 --- /dev/null +++ b/example/pop3.tmconf @@ -0,0 +1,3 @@ +ltm profile pop3 pop3 { + activation-mode require +} \ No newline at end of file diff --git a/example/test.tmconf.json b/example/test.tmconf.json index 0755901..062ed88 100644 --- a/example/test.tmconf.json +++ b/example/test.tmconf.json @@ -2666,4 +2666,4 @@ }, "route-domain": "/Common/0" } -} +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 4695445..a7c18c5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,720 +1,15 @@ { "name": "tmconfjs", - "version": "1.0.0", + "version": "1.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "tmconfjs", - "version": "1.0.0", - "license": "Apache License 2.0", - "dependencies": { - "decompress": "^4.2.1", - "winston": "^3.11.0" - }, - "bin": { - "tmconfparse": "tmconfparse.js" - } - }, - "node_modules/@colors/colors": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", - "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/@dabh/diagnostics": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", - "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", - "dependencies": { - "colorspace": "1.1.x", - "enabled": "2.0.x", - "kuler": "^2.0.0" - } - }, - "node_modules/@types/triple-beam": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", - "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" - }, - "node_modules/async": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "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/bl": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz", - "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==", - "dependencies": { - "readable-stream": "^2.3.5", - "safe-buffer": "^5.1.1" - } - }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/buffer-alloc": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", - "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", - "dependencies": { - "buffer-alloc-unsafe": "^1.1.0", - "buffer-fill": "^1.0.0" - } - }, - "node_modules/buffer-alloc-unsafe": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", - "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==" - }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "engines": { - "node": "*" - } - }, - "node_modules/buffer-fill": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", - "integrity": "sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==" - }, - "node_modules/color": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", - "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", - "dependencies": { - "color-convert": "^1.9.3", - "color-string": "^1.6.0" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "node_modules/color-string": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", - "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "node_modules/colorspace": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", - "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", - "dependencies": { - "color": "^3.1.3", - "text-hex": "1.0.x" - } - }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" - }, - "node_modules/decompress": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/decompress/-/decompress-4.2.1.tgz", - "integrity": "sha512-e48kc2IjU+2Zw8cTb6VZcJQ3lgVbS4uuB1TfCHbiZIP/haNXm+SVyhu+87jts5/3ROpd82GSVCoNs/z8l4ZOaQ==", - "dependencies": { - "decompress-tar": "^4.0.0", - "decompress-tarbz2": "^4.0.0", - "decompress-targz": "^4.0.0", - "decompress-unzip": "^4.0.1", - "graceful-fs": "^4.1.10", - "make-dir": "^1.0.0", - "pify": "^2.3.0", - "strip-dirs": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/decompress-tar": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", - "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==", - "dependencies": { - "file-type": "^5.2.0", - "is-stream": "^1.1.0", - "tar-stream": "^1.5.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/decompress-tarbz2": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz", - "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==", - "dependencies": { - "decompress-tar": "^4.1.0", - "file-type": "^6.1.0", - "is-stream": "^1.1.0", - "seek-bzip": "^1.0.5", - "unbzip2-stream": "^1.0.9" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/decompress-tarbz2/node_modules/file-type": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz", - "integrity": "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==", - "engines": { - "node": ">=4" - } - }, - "node_modules/decompress-targz": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz", - "integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==", - "dependencies": { - "decompress-tar": "^4.1.1", - "file-type": "^5.2.0", - "is-stream": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/decompress-unzip": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz", - "integrity": "sha512-1fqeluvxgnn86MOh66u8FjbtJpAFv5wgCT9Iw8rcBqQcCo5tO8eiJw7NNTrvt9n4CRBVq7CstiS922oPgyGLrw==", - "dependencies": { - "file-type": "^3.8.0", - "get-stream": "^2.2.0", - "pify": "^2.3.0", - "yauzl": "^2.4.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/decompress-unzip/node_modules/file-type": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", - "integrity": "sha512-RLoqTXE8/vPmMuTI88DAzhMYC99I8BWv7zYP4A1puo5HIjEJ5EX48ighy4ZyKMG9EDXxBgW6e++cn7d1xuFghA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/enabled": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", - "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "dependencies": { - "pend": "~1.2.0" - } - }, - "node_modules/fecha": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", - "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" - }, - "node_modules/file-type": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", - "integrity": "sha512-Iq1nJ6D2+yIO4c8HHg4fyVb8mAJieo1Oloy1mLLaB2PvezNedhBVm+QU7g0qM42aiMbRXTxKKwGD17rjKNJYVQ==", - "engines": { - "node": ">=4" - } - }, - "node_modules/fn.name": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", - "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" - }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" - }, - "node_modules/get-stream": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", - "integrity": "sha512-AUGhbbemXxrZJRD5cDvKtQxLuYaIbNtDTK8YqupCI393Q2KSTreEsLUN3ZxAWFGiKTzL6nKuzfcIvieflUX9qA==", - "dependencies": { - "object-assign": "^4.0.1", - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "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/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" - }, - "node_modules/is-natural-number": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", - "integrity": "sha512-Y4LTamMe0DDQIIAlaer9eKebAlDSV6huy+TWhJVPlzZh2o4tRP5SQWFlLn5N0To4mDD22/qdOq+veo1cSISLgQ==" - }, - "node_modules/is-stream": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, - "node_modules/kuler": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", - "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" - }, - "node_modules/logform": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz", - "integrity": "sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==", - "dependencies": { - "@colors/colors": "1.6.0", - "@types/triple-beam": "^1.3.2", - "fecha": "^4.2.0", - "ms": "^2.1.1", - "safe-stable-stringify": "^2.3.1", - "triple-beam": "^1.3.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/make-dir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", - "dependencies": { - "pify": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/make-dir/node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", - "engines": { - "node": ">=4" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/one-time": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", - "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", - "dependencies": { - "fn.name": "1.x.x" - } - }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==" - }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", - "dependencies": { - "pinkie": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/readable-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "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/safe-stable-stringify": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", - "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", - "engines": { - "node": ">=10" - } - }, - "node_modules/seek-bzip": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.6.tgz", - "integrity": "sha512-e1QtP3YL5tWww8uKaOCQ18UxIT2laNBXHjV/S2WYCiK4udiv8lkG89KRIoCjUagnAmCBurjF4zEVX2ByBbnCjQ==", - "dependencies": { - "commander": "^2.8.1" - }, + "license": "Apache License 2.0", "bin": { - "seek-bunzip": "bin/seek-bunzip", - "seek-table": "bin/seek-bzip-table" - } - }, - "node_modules/simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", - "dependencies": { - "is-arrayish": "^0.3.1" - } - }, - "node_modules/stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", - "engines": { - "node": "*" - } - }, - "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/strip-dirs": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz", - "integrity": "sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==", - "dependencies": { - "is-natural-number": "^4.0.1" - } - }, - "node_modules/tar-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", - "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", - "dependencies": { - "bl": "^1.0.0", - "buffer-alloc": "^1.2.0", - "end-of-stream": "^1.0.0", - "fs-constants": "^1.0.0", - "readable-stream": "^2.3.0", - "to-buffer": "^1.1.1", - "xtend": "^4.0.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/text-hex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", - "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" - }, - "node_modules/to-buffer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", - "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==" - }, - "node_modules/triple-beam": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", - "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/unbzip2-stream": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", - "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", - "dependencies": { - "buffer": "^5.2.1", - "through": "^2.3.8" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "node_modules/winston": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.11.0.tgz", - "integrity": "sha512-L3yR6/MzZAOl0DsysUXHVjOwv8mKZ71TrA/41EIduGpOOV5LQVodqN+QdQ6BS6PJ/RdIshZhq84P/fStEZkk7g==", - "dependencies": { - "@colors/colors": "^1.6.0", - "@dabh/diagnostics": "^2.0.2", - "async": "^3.2.3", - "is-stream": "^2.0.0", - "logform": "^2.4.0", - "one-time": "^1.0.0", - "readable-stream": "^3.4.0", - "safe-stable-stringify": "^2.3.1", - "stack-trace": "0.0.x", - "triple-beam": "^1.3.0", - "winston-transport": "^4.5.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/winston-transport": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.0.tgz", - "integrity": "sha512-ajBj65K5I7denzer2IYW6+2bNIVqLGDHqDw3Ow8Ohh+vdW+rv4MZ6eiDvHoKhfJFZ2auyN8byXieDDJ96ViONg==", - "dependencies": { - "logform": "^2.3.2", - "readable-stream": "^3.6.0", - "triple-beam": "^1.3.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/winston-transport/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/winston/node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/winston/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "engines": { - "node": ">=0.4" - } - }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" + "tmconfjs": "tmconfjs.js" } } } diff --git a/package.json b/package.json index fadeb5e..cbf9926 100644 --- a/package.json +++ b/package.json @@ -1,19 +1,22 @@ { "name": "tmconfjs", - "version": "1.0.0", + "version": "1.1.0", "description": "Parse F5 tmconf files to JSON.", - "main": "tmconfparse.js", + "main": "tmconfjs.js", + "bin": { + "tmconfjs": "./tmconfjs.js" + }, "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, - "bin": { - "tmconfparse": "./tmconfparse.js" - }, - "keywords": ["F5", "tmconf", "parse", "JSON", "BIG-IP"], + "keywords": [ + "F5", + "tmconf", + "parse", + "serialize", + "JSON", + "BIG-IP" + ], "author": "Simon Kowallik", - "license": "Apache License 2.0", - "dependencies": { - "decompress": "^4.2.1", - "winston": "^3.11.0" - } + "license": "Apache License 2.0" } diff --git a/tmconfjs.js b/tmconfjs.js new file mode 100755 index 0000000..c99e029 --- /dev/null +++ b/tmconfjs.js @@ -0,0 +1,133 @@ +#!/usr/bin/env node + +'use strict' + +const parser = require('./vendored/engines/parser') +const log = require('./vendored/util/log') +const fs = require('fs').promises + +const help = `usage: node tmconfjs.js [--output|-o ] +options: +--output, -o : File to write JSON output to. + +arguments: +: Path to tmconf file to read. + +Parses tmconf file or STDIN and writes JSON representation to STDOUT. +Logs like warnings and errors are printed to STDERR. +License: Apache-2.0, home: https://github.com/simonkowallik/tmconfjs +` + +if ( + process.argv.includes('--help') || + process.argv.includes('-h') || + process.argv.includes('--version') || + process.argv.includes('-v') +) { + console.log(help) + process.exit(0) +} + +function parse (data) { + log.log('trace', `Handing data to parser:\n${data}`) + return parser({ data }) +} + +async function parseFile (filePath) { + log.debug(`Parsing from : ${filePath}`) + const data = await fs.readFile(filePath) + return parse(data.toString()) +} + +async function readStdin () { + let data = '' + for await (const chunk of process.stdin) { + data += chunk + log.log('trace', `STDIN data received: ${chunk}`) + } + log.debug(`STDIN data read completed. Bytes read: ${data.length}`) + return data +} + +async function mainOld () { + const filePath = process.argv[2] + + if (filePath) { + // prefer argument, it's more explicit + const parsed = await parseFile(filePath) + process.stdout.write(JSON.stringify(parsed, null, 4)) + } else if (!process.stdin.isTTY) { + // use STDIN otherwise + log.debug('Parsing from ') + const parsed = parse(await readStdin()) + process.stdout.write(JSON.stringify(parsed, null, 4)) + } else { + // neither file_path nor STDIN + console.error('Error: argument or STDIN is required.') + process.exit(1) + } +} + +async function writeFile (outputFile, data) { + log.debug('Writing to : ' + outputFile) + await fs.writeFile(outputFile, data) +} + +async function main () { + let filePath = null + let outputFile = null + + // parse arguments + const args = process.argv.slice(2) + let optionValueIsNext = false + args.forEach(arg => { + if (arg === '--output' || arg === '-o') { + optionValueIsNext = true + } else if (optionValueIsNext) { + outputFile = arg + optionValueIsNext = false + } else if (filePath === null) { + filePath = arg + } + }) + + if (filePath) { + // prefer argument, it's more explicit + const parsed = await parseFile(filePath) + + if (outputFile && outputFile != '-') { + await writeFile(outputFile, JSON.stringify(parsed, null, 4)) + } else { + process.stdout.write(JSON.stringify(parsed, null, 4)) + } + } else if (!process.stdin.isTTY) { + // use STDIN otherwise + log.debug('Parsing from ') + + const parsed = parse(await readStdin()) + + if (outputFile && outputFile != '-') { + await writeFile(outputFile, JSON.stringify(parsed, null, 4)) + } else { + process.stdout.write(JSON.stringify(parsed, null, 4)) + } + } else { + // neither file_path nor STDIN + console.error('Error: argument or STDIN is required.') + process.exit(1) + } +} + +if (require.main === module) { + // only run if called directly - do not run if required as a module + main() +} + +process.stdout.on('error', (err) => { + // ignore EPIPE errors (broken pipe), eg. when piping to `head` + if (err.code === 'EPIPE') { + process.exit(0) + } +}) + +module.exports = { parse, parseFile } diff --git a/tmconfparse.js b/tmconfparse.js deleted file mode 100755 index 06af84b..0000000 --- a/tmconfparse.js +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env node - -"use strict"; - -const parser = require("./vendored/engines/parser"); -const readFiles = require("./vendored/preConverter/readFiles"); - -if (process.argv.includes("--help") || process.argv.includes("-h")) { - console.log("Usage: node tmconfparse.js "); - console.log("Reads a tmconf file and prints JSON conversion to STDOUT."); - console.log(": Path to the tmconf file to read."); - process.exit(0); -} -if (process.argv.length < 3) { - console.error("Error: A file path argument is required."); - process.exit(1); -} - -async function parse(filePath) { - const data = await readFiles([filePath]); - const parsed = parser(data); - return parsed; - -} - -const filePath = process.argv[2]; - -(async (filePath) => { - const parsed = await parse(filePath); - console.log(JSON.stringify(parsed, null, 4)); -})(filePath); - -module.exports = parse; diff --git a/vendored/README.md b/vendored/README.md index 27e6540..cd4bc66 100644 --- a/vendored/README.md +++ b/vendored/README.md @@ -1,10 +1,10 @@ # original source -https://github.com/f5devcentral/f5-automation-config-converter/tree/v1.24.0 +[https://github.com/f5devcentral/f5-automation-config-converter/tree/v1.24.0](https://github.com/f5devcentral/f5-automation-config-converter/tree/v1.24.0) # license -See ./LICENSE +See [./LICENSE](./LICENSE) # modifications @@ -13,14 +13,7 @@ Removed any unnecessary code. ## ./engines/parser.js Line 280, removed reference to original repo. -``` - e.message = `Error parsing input file. Error:\n${e.message}`; -``` - -## ./util/log.js - -Line 43, instruct winston to always log to STDERR. +```javascript + e.message = `Error parsing input file. Error:\n${e.message}`; ``` - stderrLevels: ['error', 'warn', 'info', 'verbose', 'debug', 'silly'], // All log levels will be written to stderr -``` \ No newline at end of file diff --git a/vendored/preConverter/extract.js b/vendored/preConverter/extract.js deleted file mode 100644 index 139ff49..0000000 --- a/vendored/preConverter/extract.js +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Copyright 2022 F5 Networks, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -'use strict'; - -const decompress = require('decompress'); -const log = require('../util/log'); - -// extract only relevant files from config and var -// decompress function accepts UCS path or UCS buffer -module.exports = (pathOrBuffer) => decompress(pathOrBuffer) - .then((contents) => contents.filter((file) => { - if (file.type === 'symlink') return false; - const split = file.path.split('/'); - - // keep config/*.conf - if (split[0] === 'config' && split[1].endsWith('.conf')) { - return true; - } - - // keep config/bigip.license - if (split[0] === 'config' && split[1].endsWith('.license')) { - return true; - } - - // keep config/partitions/**/*.conf - if (file.path.startsWith('config/partitions') && file.path.endsWith('.conf')) { - return true; - } - - // skip var/tmp/filestore_temp/files_d/Common_d/epsec_package_d -- KB25633150 - if (file.path.includes('epsec_package_d')) { - return false; - } - - // keep var/tmp/filestore_temp/files_d/* and var/tmp/cert_tmp/conf - if ((file.path.startsWith('var/tmp/filestore_temp/files_d/Common_d') - || file.path.startsWith('var/tmp/cert_temp/conf')) - && (file.path.endsWith('.crt') || file.path.endsWith('.key'))) { - return true; - } - - return false; - })).catch((err) => { - log.error(err); - throw new Error('Error extracting UCS'); - }); diff --git a/vendored/preConverter/readFiles.js b/vendored/preConverter/readFiles.js deleted file mode 100644 index dddf859..0000000 --- a/vendored/preConverter/readFiles.js +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Copyright 2022 F5 Networks, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -'use strict'; - -const fs = require('fs').promises; -const extract = require('./extract'); - -const fromConf = (confPath) => fs.readFile(confPath).then((data) => ({ [confPath]: data.toString() })); - -const fromUCS = (ucsPath) => extract(ucsPath) - .then((fileArr) => Object.assign({}, ...fileArr.filter((x) => x.type !== 'directory') - .filter((x) => !x.path.includes('._')) - .map((x) => ({ [x.path]: x.data.toString() })))); - -function handlePathArr(pathArr) { - return Promise.all( - pathArr.map((path) => (path.includes('.ucs') ? fromUCS(path) : fromConf(path))) - ).then((fileArr) => Object.assign({}, ...fileArr)) - .then((fileObj) => { - handlePathArr.data = fileObj; - return fileObj; - }); -} - -handlePathArr.data = {}; - -module.exports = handlePathArr; diff --git a/vendored/util/log.js b/vendored/util/log.js index 08027e5..e9ab699 100644 --- a/vendored/util/log.js +++ b/vendored/util/log.js @@ -1,71 +1,37 @@ -/** - * Copyright 2022 F5 Networks, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -'use strict'; - -const winston = require('winston'); -const Writable = require('stream').Writable; - -const colorizer = winston.format.colorize(); -let level = process.env.LOG_LEVEL || 'info'; -if (process.env.NODE_ENV === 'test') level = 'warn'; - -// var for stream log stdout into it -let output = ''; -const stream = new Writable(); -stream._write = (chunk, encoding, next) => { - output += chunk.toString(); - next(); -}; - -const logger = winston.createLogger({ - format: winston.format.combine( - winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), - winston.format.printf((msg) => `${msg.timestamp} ${msg.level.toUpperCase()} ${msg.message}`) - ), - level, - json: false, - transports: [ - new winston.transports.Console({ - stderrLevels: ['error', 'warn', 'info', 'verbose', 'debug', 'silly'], // All log levels will be written to stderr - format: winston.format.printf( - (msg) => `${msg.timestamp} ${colorizer.colorize( - msg.level, - msg.level.toUpperCase() - )} ${msg.message}` - ) - }), - new winston.transports.Stream({ stream }) - ] -}); - -logger.configure = (filename) => { - if (filename) { - logger.add(new winston.transports.File({ - filename, - json: false, - maxsize: 10000000 - })); - } -}; - -logger.memory = () => { - const arr = output.trim().split('\n'); - output = ''; - return arr; -}; - -module.exports = logger; +'use strict' + +const levels = { + emerg: 0, + alert: 1, + crit: 2, + error: 3, + warn: 4, + warning: 4, + notice: 5, + info: 6, + verbose: 7, + debug: 8, + trace: 9, + silly: 10 +} + +const currentLevel = levels[process.env.LOG_LEVEL] || levels.info + +const loggerFactory = (level, message) => { + if (currentLevel >= levels[level]) { + process.stderr.write( + `${new Date().toISOString()} ${level.toUpperCase()} ${message}` + '\n', + 'utf-8' + ) + } +} + +const logger = { + info: (message) => loggerFactory('info', message), + warn: (message) => loggerFactory('warn', message), + error: (message) => loggerFactory('error', message), + debug: (message) => loggerFactory('debug', message), + log: (level, message) => loggerFactory(level, message) +} + +module.exports = logger