From 0d1b21a4b6e7c2d4c6d326928930ac587a61020c Mon Sep 17 00:00:00 2001 From: Sebastian Alex Date: Wed, 28 Jun 2023 12:30:24 +0000 Subject: [PATCH 01/15] cli: add initial @backtrace/cli project --- package-lock.json | 15 +++++++++++++++ tools/cli/LICENSE | 21 +++++++++++++++++++++ tools/cli/package.json | 39 +++++++++++++++++++++++++++++++++++++++ tools/cli/src/index.ts | 0 tools/cli/tsconfig.json | 9 +++++++++ 5 files changed, 84 insertions(+) create mode 100644 tools/cli/LICENSE create mode 100644 tools/cli/package.json create mode 100644 tools/cli/src/index.ts create mode 100644 tools/cli/tsconfig.json diff --git a/package-lock.json b/package-lock.json index 24d922cb..48bf20ee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -610,6 +610,10 @@ "resolved": "packages/browser", "link": true }, + "node_modules/@backtrace/javascript-cli": { + "resolved": "tools/cli", + "link": true + }, "node_modules/@backtrace/node": { "resolved": "packages/node", "link": true @@ -11581,6 +11585,14 @@ "typescript": "^5.0.4" } }, + "tools/cli": { + "version": "1.0.0", + "license": "MIT", + "devDependencies": {}, + "engines": { + "node": ">=14" + } + }, "tools/sourcemap-tools": { "name": "@backtrace/sourcemap-tools", "version": "0.0.1", @@ -12029,6 +12041,9 @@ "webpack-cli": "^5.1.4" } }, + "@backtrace/javascript-cli": { + "version": "file:tools/cli" + }, "@backtrace/node": { "version": "file:packages/node", "requires": { diff --git a/tools/cli/LICENSE b/tools/cli/LICENSE new file mode 100644 index 00000000..cf679f7e --- /dev/null +++ b/tools/cli/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Backtrace Labs + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/tools/cli/package.json b/tools/cli/package.json new file mode 100644 index 00000000..b82b1712 --- /dev/null +++ b/tools/cli/package.json @@ -0,0 +1,39 @@ +{ + "name": "@backtrace/javascript-cli", + "version": "0.0.1", + "description": "Backtrace CLI for working with Javascript files.", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "engines": { + "node": ">=14" + }, + "devDependencies": {}, + "scripts": { + "build": "tsc", + "clean": "tsc -b --clean && rimraf \"lib\"", + "format": "prettier --write '**/*.ts'", + "lint": "eslint . --ext .ts", + "watch": "tsc -w" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/backtrace-labs/backtrace-javascript.git" + }, + "keywords": [ + "Error", + "Reporting", + "Diagnostic", + "Tool", + "Bug", + "Bugs", + "StackTrace", + "Source maps", + "Sourcemaps" + ], + "author": "Backtrace ", + "license": "MIT", + "bugs": { + "url": "https://github.com/backtrace-labs/backtrace-javascript/issues" + }, + "homepage": "https://github.com/backtrace-labs/backtrace-javascript#readme" +} diff --git a/tools/cli/src/index.ts b/tools/cli/src/index.ts new file mode 100644 index 00000000..e69de29b diff --git a/tools/cli/tsconfig.json b/tools/cli/tsconfig.json new file mode 100644 index 00000000..32a5f6ba --- /dev/null +++ b/tools/cli/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./lib", + "composite": true + }, + "exclude": ["node_modules", "tests", "lib"] +} From 381584a3f94d22a650fcbf829753daf6c5ab221a Mon Sep 17 00:00:00 2001 From: Sebastian Alex Date: Wed, 28 Jun 2023 12:33:17 +0000 Subject: [PATCH 02/15] cli: add command-line-args and command-line-usage package --- package-lock.json | 684 ++++++++++++++++++++++++----------------- tools/cli/package.json | 14 +- 2 files changed, 405 insertions(+), 293 deletions(-) diff --git a/package-lock.json b/package-lock.json index 48bf20ee..973d4a21 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,26 @@ "typescript": "^5.0.4" } }, + "node_modules/@75lb/deep-merge": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@75lb/deep-merge/-/deep-merge-1.1.1.tgz", + "integrity": "sha512-xvgv6pkMGBA6GwdyJbNAnDmfAIR/DfWhrj9jgWh3TY7gRm3KO46x/GPjRg6wJ0nOepwqrNxFfojebh0Df4h4Tw==", + "dependencies": { + "lodash.assignwith": "^4.2.0", + "typical": "^7.1.1" + }, + "engines": { + "node": ">=12.17" + } + }, + "node_modules/@75lb/deep-merge/node_modules/typical": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/typical/-/typical-7.1.1.tgz", + "integrity": "sha512-T+tKVNs6Wu7IWiAce5BgMd7OZfNYUndHwc5MknN+UHOudi7sGZzuHdCadllRuqJ3fPtgFtIH9+lt9qRv6lmpfA==", + "engines": { + "node": ">=12.17" + } + }, "node_modules/@ampproject/remapping": { "version": "2.2.1", "dev": true, @@ -1338,9 +1358,8 @@ }, "node_modules/@types/archiver": { "version": "5.3.2", - "resolved": "https://registry.npmjs.org/@types/archiver/-/archiver-5.3.2.tgz", - "integrity": "sha512-IctHreBuWE5dvBDz/0WeKtyVKVRs4h75IblxOACL92wU66v+HGAfEYAOyXkOFphvRJMhuXdI9huDXpX0FC6lCw==", "dev": true, + "license": "MIT", "dependencies": { "@types/readdir-glob": "*" } @@ -1387,11 +1406,21 @@ "@babel/types": "^7.20.7" } }, + "node_modules/@types/command-line-args": { + "version": "5.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/command-line-usage": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@types/command-line-usage/-/command-line-usage-5.0.2.tgz", + "integrity": "sha512-n7RlEEJ+4x4TS7ZQddTmNSxP+zziEG0TNsMfiRIxcIVXt71ENJ9ojeXmGO3wPoTdn7pJcU2xc3CJYMktNT6DPg==", + "dev": true + }, "node_modules/@types/decompress": { "version": "4.2.4", - "resolved": "https://registry.npmjs.org/@types/decompress/-/decompress-4.2.4.tgz", - "integrity": "sha512-/C8kTMRTNiNuWGl5nEyKbPiMv6HA+0RbEXzFhFBEzASM6+oa4tJro9b8nj7eRlOFfuLdzUU+DS/GPDlvvzMOhA==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -1507,9 +1536,8 @@ }, "node_modules/@types/readdir-glob": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/readdir-glob/-/readdir-glob-1.1.1.tgz", - "integrity": "sha512-ImM6TmoF8bgOwvehGviEj3tRdRBbQujr1N+0ypaln/GWjaerOB26jb93vsRHmdMtvVQZQebOlqt2HROark87mQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -2141,7 +2169,6 @@ }, "node_modules/ansi-styles": { "version": "4.3.0", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -2172,8 +2199,7 @@ }, "node_modules/archiver": { "version": "5.3.1", - "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.1.tgz", - "integrity": "sha512-8KyabkmbYrH+9ibcTScQ1xCJC/CGcugdVIwB+53f5sZziXgwUh3iXlAlANMxcZyDEfTHMe6+Z5FofV8nopXP7w==", + "license": "MIT", "dependencies": { "archiver-utils": "^2.1.0", "async": "^3.2.3", @@ -2189,8 +2215,7 @@ }, "node_modules/archiver-utils": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", - "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", + "license": "MIT", "dependencies": { "glob": "^7.1.4", "graceful-fs": "^4.2.0", @@ -2209,8 +2234,7 @@ }, "node_modules/archiver-utils/node_modules/glob": { "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -2228,8 +2252,7 @@ }, "node_modules/archiver/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==", + "license": "MIT", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -2276,6 +2299,13 @@ "node": ">=0.10.0" } }, + "node_modules/array-back": { + "version": "3.1.0", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/array-buffer-byte-length": { "version": "1.0.0", "dev": true, @@ -2404,8 +2434,7 @@ }, "node_modules/async": { "version": "3.2.4", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", - "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" + "license": "MIT" }, "node_modules/async-each": { "version": "1.0.6", @@ -2600,8 +2629,7 @@ }, "node_modules/bl": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "license": "MIT", "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -2610,8 +2638,6 @@ }, "node_modules/bl/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", @@ -2626,6 +2652,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -2633,8 +2660,7 @@ }, "node_modules/bl/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==", + "license": "MIT", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -2815,9 +2841,8 @@ }, "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==", "dev": true, + "license": "MIT", "dependencies": { "buffer-alloc-unsafe": "^1.1.0", "buffer-fill": "^1.0.0" @@ -2825,23 +2850,20 @@ }, "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==", - "dev": true + "dev": true, + "license": "MIT" }, "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==", + "license": "MIT", "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==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/buffer-from": { "version": "1.1.2", @@ -2994,7 +3016,6 @@ }, "node_modules/chalk": { "version": "4.1.2", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -3007,6 +3028,20 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/chalk-template": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/chalk-template/-/chalk-template-0.4.0.tgz", + "integrity": "sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==", + "dependencies": { + "chalk": "^4.1.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/chalk-template?sponsor=1" + } + }, "node_modules/char-regex": { "version": "1.0.2", "dev": true, @@ -3272,7 +3307,6 @@ }, "node_modules/color-convert": { "version": "2.0.1", - "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -3283,7 +3317,6 @@ }, "node_modules/color-name": { "version": "1.1.4", - "dev": true, "license": "MIT" }, "node_modules/colorette": { @@ -3301,6 +3334,49 @@ "node": ">= 0.8" } }, + "node_modules/command-line-args": { + "version": "5.2.1", + "license": "MIT", + "dependencies": { + "array-back": "^3.1.0", + "find-replace": "^3.0.0", + "lodash.camelcase": "^4.3.0", + "typical": "^4.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/command-line-usage": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-7.0.1.tgz", + "integrity": "sha512-NCyznE//MuTjwi3y84QVUGEOT+P5oto1e1Pk/jFPVdPPfsG03qpTIl3yw6etR+v73d0lXsoojRpvbru2sqePxQ==", + "dependencies": { + "array-back": "^6.2.2", + "chalk-template": "^0.4.0", + "table-layout": "^3.0.0", + "typical": "^7.1.1" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/command-line-usage/node_modules/array-back": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.2.tgz", + "integrity": "sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw==", + "engines": { + "node": ">=12.17" + } + }, + "node_modules/command-line-usage/node_modules/typical": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/typical/-/typical-7.1.1.tgz", + "integrity": "sha512-T+tKVNs6Wu7IWiAce5BgMd7OZfNYUndHwc5MknN+UHOudi7sGZzuHdCadllRuqJ3fPtgFtIH9+lt9qRv6lmpfA==", + "engines": { + "node": ">=12.17" + } + }, "node_modules/commander": { "version": "2.20.3", "license": "MIT" @@ -3317,8 +3393,7 @@ }, "node_modules/compress-commons": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.1.tgz", - "integrity": "sha512-QLdDLCKNV2dtoTorqgxngQCMA+gWXkM/Nwu7FpeBhk/RdkzimqC3jueb/FDmaZeXh+uby1jkBqE3xArsLBE5wQ==", + "license": "MIT", "dependencies": { "buffer-crc32": "^0.2.13", "crc32-stream": "^4.0.2", @@ -3331,8 +3406,7 @@ }, "node_modules/compress-commons/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==", + "license": "MIT", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -3431,8 +3505,7 @@ }, "node_modules/crc-32": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", - "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "license": "Apache-2.0", "bin": { "crc32": "bin/crc32.njs" }, @@ -3442,8 +3515,7 @@ }, "node_modules/crc32-stream": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.2.tgz", - "integrity": "sha512-DxFZ/Hk473b/muq1VJ///PMNLj0ZMnzye9thBpmjpJKCc5eMgB95aK8zCGrGfQ90cWo561Te6HK9D+j4KPdM6w==", + "license": "MIT", "dependencies": { "crc-32": "^1.2.0", "readable-stream": "^3.4.0" @@ -3454,8 +3526,7 @@ }, "node_modules/crc32-stream/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==", + "license": "MIT", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -3613,9 +3684,8 @@ }, "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==", "dev": true, + "license": "MIT", "dependencies": { "decompress-tar": "^4.0.0", "decompress-tarbz2": "^4.0.0", @@ -3632,9 +3702,8 @@ }, "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==", "dev": true, + "license": "MIT", "dependencies": { "file-type": "^5.2.0", "is-stream": "^1.1.0", @@ -3646,9 +3715,8 @@ }, "node_modules/decompress-tar/node_modules/bl": { "version": "1.2.3", - "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz", - "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==", "dev": true, + "license": "MIT", "dependencies": { "readable-stream": "^2.3.5", "safe-buffer": "^5.1.1" @@ -3656,18 +3724,16 @@ }, "node_modules/decompress-tar/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==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/decompress-tar/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==", "dev": true, + "license": "MIT", "dependencies": { "bl": "^1.0.0", "buffer-alloc": "^1.2.0", @@ -3683,9 +3749,8 @@ }, "node_modules/decompress-tarbz2": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz", - "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==", "dev": true, + "license": "MIT", "dependencies": { "decompress-tar": "^4.1.0", "file-type": "^6.1.0", @@ -3699,27 +3764,24 @@ }, "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==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/decompress-tarbz2/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==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "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==", "dev": true, + "license": "MIT", "dependencies": { "decompress-tar": "^4.1.1", "file-type": "^5.2.0", @@ -3731,18 +3793,16 @@ }, "node_modules/decompress-targz/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==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/decompress-unzip": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz", - "integrity": "sha512-1fqeluvxgnn86MOh66u8FjbtJpAFv5wgCT9Iw8rcBqQcCo5tO8eiJw7NNTrvt9n4CRBVq7CstiS922oPgyGLrw==", "dev": true, + "license": "MIT", "dependencies": { "file-type": "^3.8.0", "get-stream": "^2.2.0", @@ -3755,18 +3815,16 @@ }, "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==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/decompress-unzip/node_modules/get-stream": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", - "integrity": "sha512-AUGhbbemXxrZJRD5cDvKtQxLuYaIbNtDTK8YqupCI393Q2KSTreEsLUN3ZxAWFGiKTzL6nKuzfcIvieflUX9qA==", "dev": true, + "license": "MIT", "dependencies": { "object-assign": "^4.0.1", "pinkie-promise": "^2.0.0" @@ -3777,18 +3835,16 @@ }, "node_modules/decompress-unzip/node_modules/pify": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/decompress/node_modules/make-dir": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", "dev": true, + "license": "MIT", "dependencies": { "pify": "^3.0.0" }, @@ -3798,18 +3854,16 @@ }, "node_modules/decompress/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==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/decompress/node_modules/pify": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -4920,9 +4974,8 @@ }, "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==", "dev": true, + "license": "MIT", "dependencies": { "pend": "~1.2.0" } @@ -4945,9 +4998,8 @@ }, "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==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -5063,6 +5115,16 @@ "semver": "bin/semver" } }, + "node_modules/find-replace": { + "version": "3.0.0", + "license": "MIT", + "dependencies": { + "array-back": "^3.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/find-up": { "version": "5.0.0", "dev": true, @@ -5202,8 +5264,7 @@ }, "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==" + "license": "MIT" }, "node_modules/fs-write-stream-atomic": { "version": "1.0.10", @@ -6006,9 +6067,8 @@ }, "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==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/is-negative-zero": { "version": "2.0.2", @@ -7032,8 +7092,7 @@ }, "node_modules/lazystream": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", - "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "license": "MIT", "dependencies": { "readable-stream": "^2.0.5" }, @@ -7116,25 +7175,30 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.assignwith": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assignwith/-/lodash.assignwith-4.2.0.tgz", + "integrity": "sha512-ZznplvbvtjK2gMvnQ1BR/zqPFZmS6jbK4p+6Up4xcRYA7yMIwxHCfbTcrYxXKzzqLsQ05eJPVznEW3tuwV7k1g==" + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "license": "MIT" + }, "node_modules/lodash.defaults": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==" + "license": "MIT" }, "node_modules/lodash.difference": { "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", - "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==" + "license": "MIT" }, "node_modules/lodash.flatten": { "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", - "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==" + "license": "MIT" }, "node_modules/lodash.isplainobject": { "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + "license": "MIT" }, "node_modules/lodash.memoize": { "version": "4.1.2", @@ -7148,8 +7212,7 @@ }, "node_modules/lodash.union": { "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", - "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==" + "license": "MIT" }, "node_modules/loose-envify": { "version": "1.4.0", @@ -7980,9 +8043,8 @@ }, "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==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/picocolors": { "version": "1.0.0", @@ -8009,18 +8071,16 @@ }, "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==", "dev": true, + "license": "MIT", "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==", "dev": true, + "license": "MIT", "dependencies": { "pinkie": "^2.0.0" }, @@ -8380,24 +8440,21 @@ }, "node_modules/readdir-glob": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", - "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", + "license": "Apache-2.0", "dependencies": { "minimatch": "^5.1.0" } }, "node_modules/readdir-glob/node_modules/brace-expansion": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/readdir-glob/node_modules/minimatch": { "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -8707,9 +8764,8 @@ }, "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==", "dev": true, + "license": "MIT", "dependencies": { "commander": "^2.8.1" }, @@ -9257,6 +9313,14 @@ "xtend": "^4.0.0" } }, + "node_modules/stream-read-all": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/stream-read-all/-/stream-read-all-3.0.1.tgz", + "integrity": "sha512-EWZT9XOceBPlVJRrYcykW8jyRSZYbkb/0ZK36uLEmoWVO5gxBOnntNTseNzfREsqxqdfEGQrD8SXQ3QWbBmq8A==", + "engines": { + "node": ">=10" + } + }, "node_modules/stream-shift": { "version": "1.0.1", "dev": true, @@ -9416,9 +9480,8 @@ }, "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==", "dev": true, + "license": "MIT", "dependencies": { "is-natural-number": "^4.0.1" } @@ -9444,7 +9507,6 @@ }, "node_modules/supports-color": { "version": "7.2.0", - "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -9469,6 +9531,42 @@ "dev": true, "license": "MIT" }, + "node_modules/table-layout": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-3.0.2.tgz", + "integrity": "sha512-rpyNZYRw+/C+dYkcQ3Pr+rLxW4CfHpXjPDnG7lYhdRoUcZTUt+KEsX+94RGp/aVp/MQU35JCITv2T/beY4m+hw==", + "dependencies": { + "@75lb/deep-merge": "^1.1.1", + "array-back": "^6.2.2", + "command-line-args": "^5.2.1", + "command-line-usage": "^7.0.0", + "stream-read-all": "^3.0.1", + "typical": "^7.1.1", + "wordwrapjs": "^5.1.0" + }, + "bin": { + "table-layout": "bin/cli.js" + }, + "engines": { + "node": ">=12.17" + } + }, + "node_modules/table-layout/node_modules/array-back": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.2.tgz", + "integrity": "sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw==", + "engines": { + "node": ">=12.17" + } + }, + "node_modules/table-layout/node_modules/typical": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/typical/-/typical-7.1.1.tgz", + "integrity": "sha512-T+tKVNs6Wu7IWiAce5BgMd7OZfNYUndHwc5MknN+UHOudi7sGZzuHdCadllRuqJ3fPtgFtIH9+lt9qRv6lmpfA==", + "engines": { + "node": ">=12.17" + } + }, "node_modules/tapable": { "version": "2.2.1", "license": "MIT", @@ -9478,8 +9576,7 @@ }, "node_modules/tar-stream": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "license": "MIT", "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", @@ -9493,8 +9590,7 @@ }, "node_modules/tar-stream/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==", + "license": "MIT", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -9624,9 +9720,8 @@ }, "node_modules/through": { "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/through2": { "version": "2.0.5", @@ -9660,9 +9755,8 @@ }, "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==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/to-fast-properties": { "version": "2.0.0", @@ -9962,6 +10056,13 @@ "node": ">=12.20" } }, + "node_modules/typical": { + "version": "4.0.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/ua-parser-js": { "version": "1.0.35", "funding": [ @@ -9995,9 +10096,8 @@ }, "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==", "dev": true, + "license": "MIT", "dependencies": { "buffer": "^5.2.1", "through": "^2.3.8" @@ -10005,8 +10105,6 @@ }, "node_modules/unbzip2-stream/node_modules/buffer": { "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "dev": true, "funding": [ { @@ -10022,6 +10120,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -11250,6 +11349,14 @@ "node": ">=0.10.0" } }, + "node_modules/wordwrapjs": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-5.1.0.tgz", + "integrity": "sha512-JNjcULU2e4KJwUNv6CHgI46UvDGitb6dGryHajXTDiLgg1/RiGoPSDw4kZfYnwGtEXf2ZMeIewDQgFGzkCB2Sg==", + "engines": { + "node": ">=12.17" + } + }, "node_modules/worker-farm": { "version": "1.7.0", "dev": true, @@ -11465,9 +11572,8 @@ }, "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==", "dev": true, + "license": "MIT", "dependencies": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" @@ -11486,8 +11592,7 @@ }, "node_modules/zip-stream": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.0.tgz", - "integrity": "sha512-zshzwQW7gG7hjpBlgeQP9RuyPGNxvJdzR8SUM3QhxCnLjWN2E7j3dOvpeDcQoETfHx0urRS7EtmVToql7YpU4A==", + "license": "MIT", "dependencies": { "archiver-utils": "^2.1.0", "compress-commons": "^4.1.0", @@ -11499,8 +11604,7 @@ }, "node_modules/zip-stream/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==", + "license": "MIT", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -11586,9 +11690,17 @@ } }, "tools/cli": { - "version": "1.0.0", + "name": "@backtrace/javascript-cli", + "version": "0.0.1", "license": "MIT", - "devDependencies": {}, + "dependencies": { + "command-line-args": "^5.2.1", + "command-line-usage": "^7.0.1" + }, + "devDependencies": { + "@types/command-line-args": "^5.2.0", + "@types/command-line-usage": "^5.0.2" + }, "engines": { "node": ">=14" } @@ -11617,8 +11729,7 @@ }, "tools/sourcemap-tools/node_modules/source-map": { "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "license": "BSD-3-Clause", "engines": { "node": ">= 8" } @@ -11652,6 +11763,22 @@ } }, "dependencies": { + "@75lb/deep-merge": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@75lb/deep-merge/-/deep-merge-1.1.1.tgz", + "integrity": "sha512-xvgv6pkMGBA6GwdyJbNAnDmfAIR/DfWhrj9jgWh3TY7gRm3KO46x/GPjRg6wJ0nOepwqrNxFfojebh0Df4h4Tw==", + "requires": { + "lodash.assignwith": "^4.2.0", + "typical": "^7.1.1" + }, + "dependencies": { + "typical": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/typical/-/typical-7.1.1.tgz", + "integrity": "sha512-T+tKVNs6Wu7IWiAce5BgMd7OZfNYUndHwc5MknN+UHOudi7sGZzuHdCadllRuqJ3fPtgFtIH9+lt9qRv6lmpfA==" + } + } + }, "@ampproject/remapping": { "version": "2.2.1", "dev": true, @@ -12042,7 +12169,13 @@ } }, "@backtrace/javascript-cli": { - "version": "file:tools/cli" + "version": "file:tools/cli", + "requires": { + "@types/command-line-args": "^5.2.0", + "@types/command-line-usage": "^5.0.2", + "command-line-args": "^5.2.1", + "command-line-usage": "^7.0.1" + } }, "@backtrace/node": { "version": "file:packages/node", @@ -12102,9 +12235,7 @@ }, "dependencies": { "source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==" + "version": "0.7.4" } } }, @@ -12603,8 +12734,6 @@ }, "@types/archiver": { "version": "5.3.2", - "resolved": "https://registry.npmjs.org/@types/archiver/-/archiver-5.3.2.tgz", - "integrity": "sha512-IctHreBuWE5dvBDz/0WeKtyVKVRs4h75IblxOACL92wU66v+HGAfEYAOyXkOFphvRJMhuXdI9huDXpX0FC6lCw==", "dev": true, "requires": { "@types/readdir-glob": "*" @@ -12647,10 +12776,18 @@ "@babel/types": "^7.20.7" } }, + "@types/command-line-args": { + "version": "5.2.0", + "dev": true + }, + "@types/command-line-usage": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@types/command-line-usage/-/command-line-usage-5.0.2.tgz", + "integrity": "sha512-n7RlEEJ+4x4TS7ZQddTmNSxP+zziEG0TNsMfiRIxcIVXt71ENJ9ojeXmGO3wPoTdn7pJcU2xc3CJYMktNT6DPg==", + "dev": true + }, "@types/decompress": { "version": "4.2.4", - "resolved": "https://registry.npmjs.org/@types/decompress/-/decompress-4.2.4.tgz", - "integrity": "sha512-/C8kTMRTNiNuWGl5nEyKbPiMv6HA+0RbEXzFhFBEzASM6+oa4tJro9b8nj7eRlOFfuLdzUU+DS/GPDlvvzMOhA==", "dev": true, "requires": { "@types/node": "*" @@ -12751,8 +12888,6 @@ }, "@types/readdir-glob": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/readdir-glob/-/readdir-glob-1.1.1.tgz", - "integrity": "sha512-ImM6TmoF8bgOwvehGviEj3tRdRBbQujr1N+0ypaln/GWjaerOB26jb93vsRHmdMtvVQZQebOlqt2HROark87mQ==", "dev": true, "requires": { "@types/node": "*" @@ -13177,7 +13312,6 @@ }, "ansi-styles": { "version": "4.3.0", - "dev": true, "requires": { "color-convert": "^2.0.1" } @@ -13196,8 +13330,6 @@ }, "archiver": { "version": "5.3.1", - "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.1.tgz", - "integrity": "sha512-8KyabkmbYrH+9ibcTScQ1xCJC/CGcugdVIwB+53f5sZziXgwUh3iXlAlANMxcZyDEfTHMe6+Z5FofV8nopXP7w==", "requires": { "archiver-utils": "^2.1.0", "async": "^3.2.3", @@ -13210,8 +13342,6 @@ "dependencies": { "readable-stream": { "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -13222,8 +13352,6 @@ }, "archiver-utils": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", - "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", "requires": { "glob": "^7.1.4", "graceful-fs": "^4.2.0", @@ -13239,8 +13367,6 @@ "dependencies": { "glob": { "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -13275,6 +13401,9 @@ "version": "3.1.0", "dev": true }, + "array-back": { + "version": "3.1.0" + }, "array-buffer-byte-length": { "version": "1.0.0", "dev": true, @@ -13364,9 +13493,7 @@ "dev": true }, "async": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", - "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" + "version": "3.2.4" }, "async-each": { "version": "1.0.6", @@ -13483,8 +13610,6 @@ }, "bl": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "requires": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -13493,8 +13618,6 @@ "dependencies": { "buffer": { "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "requires": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -13502,8 +13625,6 @@ }, "readable-stream": { "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -13644,8 +13765,6 @@ }, "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==", "dev": true, "requires": { "buffer-alloc-unsafe": "^1.1.0", @@ -13654,19 +13773,13 @@ }, "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==", "dev": true }, "buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==" + "version": "0.2.13" }, "buffer-fill": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", - "integrity": "sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==", "dev": true }, "buffer-from": { @@ -13773,12 +13886,19 @@ }, "chalk": { "version": "4.1.2", - "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, + "chalk-template": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/chalk-template/-/chalk-template-0.4.0.tgz", + "integrity": "sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==", + "requires": { + "chalk": "^4.1.2" + } + }, "char-regex": { "version": "1.0.2", "dev": true @@ -13955,14 +14075,12 @@ }, "color-convert": { "version": "2.0.1", - "dev": true, "requires": { "color-name": "~1.1.4" } }, "color-name": { - "version": "1.1.4", - "dev": true + "version": "1.1.4" }, "colorette": { "version": "2.0.20", @@ -13974,6 +14092,38 @@ "delayed-stream": "~1.0.0" } }, + "command-line-args": { + "version": "5.2.1", + "requires": { + "array-back": "^3.1.0", + "find-replace": "^3.0.0", + "lodash.camelcase": "^4.3.0", + "typical": "^4.0.0" + } + }, + "command-line-usage": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-7.0.1.tgz", + "integrity": "sha512-NCyznE//MuTjwi3y84QVUGEOT+P5oto1e1Pk/jFPVdPPfsG03qpTIl3yw6etR+v73d0lXsoojRpvbru2sqePxQ==", + "requires": { + "array-back": "^6.2.2", + "chalk-template": "^0.4.0", + "table-layout": "^3.0.0", + "typical": "^7.1.1" + }, + "dependencies": { + "array-back": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.2.tgz", + "integrity": "sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw==" + }, + "typical": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/typical/-/typical-7.1.1.tgz", + "integrity": "sha512-T+tKVNs6Wu7IWiAce5BgMd7OZfNYUndHwc5MknN+UHOudi7sGZzuHdCadllRuqJ3fPtgFtIH9+lt9qRv6lmpfA==" + } + } + }, "commander": { "version": "2.20.3" }, @@ -13987,8 +14137,6 @@ }, "compress-commons": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.1.tgz", - "integrity": "sha512-QLdDLCKNV2dtoTorqgxngQCMA+gWXkM/Nwu7FpeBhk/RdkzimqC3jueb/FDmaZeXh+uby1jkBqE3xArsLBE5wQ==", "requires": { "buffer-crc32": "^0.2.13", "crc32-stream": "^4.0.2", @@ -13998,8 +14146,6 @@ "dependencies": { "readable-stream": { "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -14074,14 +14220,10 @@ "version": "1.0.3" }, "crc-32": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", - "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==" + "version": "1.2.2" }, "crc32-stream": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.2.tgz", - "integrity": "sha512-DxFZ/Hk473b/muq1VJ///PMNLj0ZMnzye9thBpmjpJKCc5eMgB95aK8zCGrGfQ90cWo561Te6HK9D+j4KPdM6w==", "requires": { "crc-32": "^1.2.0", "readable-stream": "^3.4.0" @@ -14089,8 +14231,6 @@ "dependencies": { "readable-stream": { "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -14213,8 +14353,6 @@ }, "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==", "dev": true, "requires": { "decompress-tar": "^4.0.0", @@ -14229,8 +14367,6 @@ "dependencies": { "make-dir": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", "dev": true, "requires": { "pify": "^3.0.0" @@ -14238,24 +14374,18 @@ "dependencies": { "pify": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", "dev": true } } }, "pify": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", "dev": true } } }, "decompress-tar": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", - "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==", "dev": true, "requires": { "file-type": "^5.2.0", @@ -14265,8 +14395,6 @@ "dependencies": { "bl": { "version": "1.2.3", - "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz", - "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==", "dev": true, "requires": { "readable-stream": "^2.3.5", @@ -14275,14 +14403,10 @@ }, "is-stream": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", "dev": true }, "tar-stream": { "version": "1.6.2", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", - "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", "dev": true, "requires": { "bl": "^1.0.0", @@ -14298,8 +14422,6 @@ }, "decompress-tarbz2": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz", - "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==", "dev": true, "requires": { "decompress-tar": "^4.1.0", @@ -14311,22 +14433,16 @@ "dependencies": { "file-type": { "version": "6.2.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz", - "integrity": "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==", "dev": true }, "is-stream": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", "dev": true } } }, "decompress-targz": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz", - "integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==", "dev": true, "requires": { "decompress-tar": "^4.1.1", @@ -14336,16 +14452,12 @@ "dependencies": { "is-stream": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", "dev": true } } }, "decompress-unzip": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz", - "integrity": "sha512-1fqeluvxgnn86MOh66u8FjbtJpAFv5wgCT9Iw8rcBqQcCo5tO8eiJw7NNTrvt9n4CRBVq7CstiS922oPgyGLrw==", "dev": true, "requires": { "file-type": "^3.8.0", @@ -14356,14 +14468,10 @@ "dependencies": { "file-type": { "version": "3.9.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", - "integrity": "sha512-RLoqTXE8/vPmMuTI88DAzhMYC99I8BWv7zYP4A1puo5HIjEJ5EX48ighy4ZyKMG9EDXxBgW6e++cn7d1xuFghA==", "dev": true }, "get-stream": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", - "integrity": "sha512-AUGhbbemXxrZJRD5cDvKtQxLuYaIbNtDTK8YqupCI393Q2KSTreEsLUN3ZxAWFGiKTzL6nKuzfcIvieflUX9qA==", "dev": true, "requires": { "object-assign": "^4.0.1", @@ -14372,8 +14480,6 @@ }, "pify": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", "dev": true } } @@ -15152,8 +15258,6 @@ }, "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==", "dev": true, "requires": { "pend": "~1.2.0" @@ -15172,8 +15276,6 @@ }, "file-type": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", - "integrity": "sha512-Iq1nJ6D2+yIO4c8HHg4fyVb8mAJieo1Oloy1mLLaB2PvezNedhBVm+QU7g0qM42aiMbRXTxKKwGD17rjKNJYVQ==", "dev": true }, "fill-range": { @@ -15246,6 +15348,12 @@ } } }, + "find-replace": { + "version": "3.0.0", + "requires": { + "array-back": "^3.0.1" + } + }, "find-up": { "version": "5.0.0", "dev": true, @@ -15338,9 +15446,7 @@ } }, "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==" + "version": "1.0.0" }, "fs-write-stream-atomic": { "version": "1.0.10", @@ -15829,8 +15935,6 @@ }, "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==", "dev": true }, "is-negative-zero": { @@ -16504,8 +16608,6 @@ }, "lazystream": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", - "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", "requires": { "readable-stream": "^2.0.5" } @@ -16555,25 +16657,25 @@ "version": "4.17.21", "dev": true }, - "lodash.defaults": { + "lodash.assignwith": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==" + "resolved": "https://registry.npmjs.org/lodash.assignwith/-/lodash.assignwith-4.2.0.tgz", + "integrity": "sha512-ZznplvbvtjK2gMvnQ1BR/zqPFZmS6jbK4p+6Up4xcRYA7yMIwxHCfbTcrYxXKzzqLsQ05eJPVznEW3tuwV7k1g==" + }, + "lodash.camelcase": { + "version": "4.3.0" + }, + "lodash.defaults": { + "version": "4.2.0" }, "lodash.difference": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", - "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==" + "version": "4.5.0" }, "lodash.flatten": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", - "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==" + "version": "4.4.0" }, "lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + "version": "4.0.6" }, "lodash.memoize": { "version": "4.1.2", @@ -16584,9 +16686,7 @@ "dev": true }, "lodash.union": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", - "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==" + "version": "4.6.0" }, "loose-envify": { "version": "1.4.0", @@ -17145,8 +17245,6 @@ }, "pend": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", "dev": true }, "picocolors": { @@ -17162,14 +17260,10 @@ }, "pinkie": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", "dev": true }, "pinkie-promise": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", "dev": true, "requires": { "pinkie": "^2.0.0" @@ -17405,24 +17499,18 @@ }, "readdir-glob": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", - "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", "requires": { "minimatch": "^5.1.0" }, "dependencies": { "brace-expansion": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "requires": { "balanced-match": "^1.0.0" } }, "minimatch": { "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "requires": { "brace-expansion": "^2.0.1" } @@ -17605,8 +17693,6 @@ }, "seek-bzip": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.6.tgz", - "integrity": "sha512-e1QtP3YL5tWww8uKaOCQ18UxIT2laNBXHjV/S2WYCiK4udiv8lkG89KRIoCjUagnAmCBurjF4zEVX2ByBbnCjQ==", "dev": true, "requires": { "commander": "^2.8.1" @@ -17993,6 +18079,11 @@ "xtend": "^4.0.0" } }, + "stream-read-all": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/stream-read-all/-/stream-read-all-3.0.1.tgz", + "integrity": "sha512-EWZT9XOceBPlVJRrYcykW8jyRSZYbkb/0ZK36uLEmoWVO5gxBOnntNTseNzfREsqxqdfEGQrD8SXQ3QWbBmq8A==" + }, "stream-shift": { "version": "1.0.1", "dev": true @@ -18095,8 +18186,6 @@ }, "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==", "dev": true, "requires": { "is-natural-number": "^4.0.1" @@ -18112,7 +18201,6 @@ }, "supports-color": { "version": "7.2.0", - "dev": true, "requires": { "has-flag": "^4.0.0" } @@ -18125,13 +18213,37 @@ "version": "3.2.4", "dev": true }, + "table-layout": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-3.0.2.tgz", + "integrity": "sha512-rpyNZYRw+/C+dYkcQ3Pr+rLxW4CfHpXjPDnG7lYhdRoUcZTUt+KEsX+94RGp/aVp/MQU35JCITv2T/beY4m+hw==", + "requires": { + "@75lb/deep-merge": "^1.1.1", + "array-back": "^6.2.2", + "command-line-args": "^5.2.1", + "command-line-usage": "^7.0.0", + "stream-read-all": "^3.0.1", + "typical": "^7.1.1", + "wordwrapjs": "^5.1.0" + }, + "dependencies": { + "array-back": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.2.tgz", + "integrity": "sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw==" + }, + "typical": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/typical/-/typical-7.1.1.tgz", + "integrity": "sha512-T+tKVNs6Wu7IWiAce5BgMd7OZfNYUndHwc5MknN+UHOudi7sGZzuHdCadllRuqJ3fPtgFtIH9+lt9qRv6lmpfA==" + } + } + }, "tapable": { "version": "2.2.1" }, "tar-stream": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", "requires": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", @@ -18142,8 +18254,6 @@ "dependencies": { "readable-stream": { "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -18225,8 +18335,6 @@ }, "through": { "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", "dev": true }, "through2": { @@ -18254,8 +18362,6 @@ }, "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==", "dev": true }, "to-fast-properties": { @@ -18433,6 +18539,9 @@ "version": "5.0.4", "dev": true }, + "typical": { + "version": "4.0.0" + }, "ua-parser-js": { "version": "1.0.35" }, @@ -18448,8 +18557,6 @@ }, "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==", "dev": true, "requires": { "buffer": "^5.2.1", @@ -18458,8 +18565,6 @@ "dependencies": { "buffer": { "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "dev": true, "requires": { "base64-js": "^1.3.1", @@ -19339,6 +19444,11 @@ "version": "1.2.3", "dev": true }, + "wordwrapjs": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-5.1.0.tgz", + "integrity": "sha512-JNjcULU2e4KJwUNv6CHgI46UvDGitb6dGryHajXTDiLgg1/RiGoPSDw4kZfYnwGtEXf2ZMeIewDQgFGzkCB2Sg==" + }, "worker-farm": { "version": "1.7.0", "dev": true, @@ -19472,8 +19582,6 @@ }, "yauzl": { "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", "dev": true, "requires": { "buffer-crc32": "~0.2.3", @@ -19486,8 +19594,6 @@ }, "zip-stream": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.0.tgz", - "integrity": "sha512-zshzwQW7gG7hjpBlgeQP9RuyPGNxvJdzR8SUM3QhxCnLjWN2E7j3dOvpeDcQoETfHx0urRS7EtmVToql7YpU4A==", "requires": { "archiver-utils": "^2.1.0", "compress-commons": "^4.1.0", @@ -19496,8 +19602,6 @@ "dependencies": { "readable-stream": { "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", diff --git a/tools/cli/package.json b/tools/cli/package.json index b82b1712..15616d09 100644 --- a/tools/cli/package.json +++ b/tools/cli/package.json @@ -7,13 +7,13 @@ "engines": { "node": ">=14" }, - "devDependencies": {}, "scripts": { "build": "tsc", "clean": "tsc -b --clean && rimraf \"lib\"", "format": "prettier --write '**/*.ts'", "lint": "eslint . --ext .ts", - "watch": "tsc -w" + "watch": "tsc -w", + "start": "node lib/index.js" }, "repository": { "type": "git", @@ -35,5 +35,13 @@ "bugs": { "url": "https://github.com/backtrace-labs/backtrace-javascript/issues" }, - "homepage": "https://github.com/backtrace-labs/backtrace-javascript#readme" + "homepage": "https://github.com/backtrace-labs/backtrace-javascript#readme", + "dependencies": { + "command-line-args": "^5.2.1", + "command-line-usage": "^7.0.1" + }, + "devDependencies": { + "@types/command-line-args": "^5.2.0", + "@types/command-line-usage": "^5.0.2" + } } From b7daa13a0a84f2306b59c9768dbc5729db3da812 Mon Sep 17 00:00:00 2001 From: Sebastian Alex Date: Tue, 4 Jul 2023 08:20:12 +0000 Subject: [PATCH 03/15] cli: add commands support --- tools/cli/src/commands/Command.ts | 153 +++++++++++++++++++++++ tools/cli/src/index.ts | 22 ++++ tools/cli/src/models/CommandError.ts | 7 ++ tools/cli/src/models/OptionDefinition.ts | 6 + 4 files changed, 188 insertions(+) create mode 100644 tools/cli/src/commands/Command.ts create mode 100644 tools/cli/src/models/CommandError.ts create mode 100644 tools/cli/src/models/OptionDefinition.ts diff --git a/tools/cli/src/commands/Command.ts b/tools/cli/src/commands/Command.ts new file mode 100644 index 00000000..60e3cbf7 --- /dev/null +++ b/tools/cli/src/commands/Command.ts @@ -0,0 +1,153 @@ +import { Err, Ok, Result } from '@backtrace/sourcemap-tools'; +import commandLineArgs from 'command-line-args'; +import commandLineUsage, { Section } from 'command-line-usage'; +import { CommandError } from '../models/CommandError'; +import { ExtendedOptionDefinition } from '../models/OptionDefinition'; + +export class Command { + public readonly subcommands: Command[] = []; + public readonly options: ExtendedOptionDefinition[] = []; + public readonly helpSections: Section[] = []; + private _execute?: (values: Partial) => Result | Promise>; + + constructor(public readonly definition: ExtendedOptionDefinition) {} + + public subcommand(command: Command): this { + this.subcommands.push(command); + return this; + } + + public option(option: ExtendedOptionDefinition): this { + this.options.push(option); + return this; + } + + public help(...sections: Section[]): this { + this.helpSections.push(...sections); + return this; + } + + public execute(fn: Command['_execute']): this { + this._execute = fn; + return this; + } + + public async run(argv: string[], stack?: Command[]): Promise> { + const stackOptions = stack?.flatMap((s) => s.options.filter((o) => o.global)) ?? []; + const localOptions = [...this.options, ...stackOptions]; + const subcommandOption = { + name: '_subcommand', + defaultOption: true, + }; + + const subCommandMode = !!this.subcommands.length; + if (subCommandMode) { + localOptions.push(subcommandOption); + } + + const values = commandLineArgs(localOptions, { + argv, + stopAtFirstUnknown: subCommandMode, + }); + + if (subCommandMode && values._subcommand) { + const subcommand = this.subcommands.find((s) => s.definition.name === values._subcommand); + if (subcommand) { + const subcommandValues = commandLineArgs([subcommandOption], { argv, stopAtFirstUnknown: true }); + return await subcommand.run(subcommandValues._unknown ?? [], [...(stack ?? []), this]); + } + } + + if (values.help) { + this.displayHelp(stack); + return Ok(0); + } + + if (this._execute) { + return (await this._execute(values as T)).mapErr((error) => ({ command: this, error, stack })); + } + + if (subCommandMode) { + return Err({ command: this, stack, error: 'Unknown command.' }); + } + + return Err({ command: this, stack, error: 'Unknown option.' }); + } + + public displayHelp(stack?: Command[]) { + const globalOptions = [ + ...this.options.filter((o) => o.global), + ...(stack?.flatMap((o) => o.options.filter((o) => o.global)) ?? []), + ]; + + const nonGlobalOptions = this.options.filter((o) => !o.global); + + let cmd = 'backtrace'; + const stackCmd = `${ + [...(stack ?? []), this] + .map((s) => s.definition.name) + .filter((s) => !!s) + .join(' ') ?? '' + }`; + + if (stackCmd) { + cmd += ` ${stackCmd}`; + } + + let usage = cmd; + if (this.subcommands.length) { + usage += ' '; + } + + const defaultOption = + nonGlobalOptions.find((s) => s.defaultOption) ?? globalOptions.find((s) => s.defaultOption); + if (defaultOption) { + usage += ` <${defaultOption.name}>`; + } + + if (globalOptions.length + nonGlobalOptions.length) { + usage += ' [options]'; + } + + const sections: Section[] = [ + { + header: cmd, + content: 'Backtrace utility for managing Javascript files.', + }, + ]; + + if (this.helpSections.length) { + sections.push(...this.helpSections); + } + + sections.push({ + content: `Usage: ${usage}`, + }); + + if (this.subcommands.length) { + sections.push({ + header: 'Available commands', + content: this.subcommands.map((s) => ({ + name: s.definition.name, + summary: s.definition.description, + })), + }); + } + + if (nonGlobalOptions.length) { + sections.push({ + header: 'Available options', + optionList: nonGlobalOptions, + }); + } + + if (globalOptions.length) { + sections.push({ + header: 'Global options', + optionList: globalOptions, + }); + } + + console.error(commandLineUsage(sections)); + } +} diff --git a/tools/cli/src/index.ts b/tools/cli/src/index.ts index e69de29b..c55b9bcd 100644 --- a/tools/cli/src/index.ts +++ b/tools/cli/src/index.ts @@ -0,0 +1,22 @@ +import { Command } from './commands/Command'; + +const mainCommand: Command = new Command({ + name: '', +}).option({ + name: 'help', + type: Boolean, + alias: 'h', + global: true, + description: 'Displays this help message.', +}); + +(async () => { + const result = await mainCommand.run(process.argv); + if (result.isOk()) { + process.exit(result.data); + } else { + console.error(`Error: ${result.data.error}`); + result.data.command.displayHelp(result.data.stack); + process.exit(1); + } +})(); diff --git a/tools/cli/src/models/CommandError.ts b/tools/cli/src/models/CommandError.ts new file mode 100644 index 00000000..a7eaa49c --- /dev/null +++ b/tools/cli/src/models/CommandError.ts @@ -0,0 +1,7 @@ +import { Command } from '../commands/Command'; + +export interface CommandError { + readonly command: Command; + readonly stack?: Command[]; + readonly error: string | Error; +} diff --git a/tools/cli/src/models/OptionDefinition.ts b/tools/cli/src/models/OptionDefinition.ts new file mode 100644 index 00000000..9f9285de --- /dev/null +++ b/tools/cli/src/models/OptionDefinition.ts @@ -0,0 +1,6 @@ +import { OptionDefinition } from 'command-line-usage'; + +export interface ExtendedOptionDefinition extends OptionDefinition { + readonly name: N; + readonly global?: boolean; +} From 76351de3597c6a47ad48214d02f6d4ae2edf2a21 Mon Sep 17 00:00:00 2001 From: Sebastian Alex Date: Wed, 5 Jul 2023 10:15:37 +0000 Subject: [PATCH 04/15] cli: add logger implementation and usage --- tools/cli/src/commands/Command.ts | 23 ++++-- tools/cli/src/index.ts | 49 ++++++++++--- tools/cli/src/logger.ts | 112 ++++++++++++++++++++++++++++++ 3 files changed, 169 insertions(+), 15 deletions(-) create mode 100644 tools/cli/src/logger.ts diff --git a/tools/cli/src/commands/Command.ts b/tools/cli/src/commands/Command.ts index 60e3cbf7..234fa007 100644 --- a/tools/cli/src/commands/Command.ts +++ b/tools/cli/src/commands/Command.ts @@ -1,6 +1,7 @@ import { Err, Ok, Result } from '@backtrace/sourcemap-tools'; import commandLineArgs from 'command-line-args'; import commandLineUsage, { Section } from 'command-line-usage'; +import { LoggerOptions, createLogger } from '../logger'; import { CommandError } from '../models/CommandError'; import { ExtendedOptionDefinition } from '../models/OptionDefinition'; @@ -8,7 +9,11 @@ export class Command { public readonly subcommands: Command[] = []; public readonly options: ExtendedOptionDefinition[] = []; public readonly helpSections: Section[] = []; - private _execute?: (values: Partial) => Result | Promise>; + private _execute?: ( + this: this, + values: Partial, + stack?: Command[], + ) => Result | Promise>; constructor(public readonly definition: ExtendedOptionDefinition) {} @@ -58,15 +63,23 @@ export class Command { } } + const logger = createLogger(values as LoggerOptions); + if (values.help) { - this.displayHelp(stack); + logger.output(this.getHelpMessage(stack)); return Ok(0); } if (this._execute) { - return (await this._execute(values as T)).mapErr((error) => ({ command: this, error, stack })); + return (await this._execute.call(this, values as T, stack)).mapErr((error) => ({ + command: this, + error, + stack, + })); } + logger.info(this.getHelpMessage(stack)); + if (subCommandMode) { return Err({ command: this, stack, error: 'Unknown command.' }); } @@ -74,7 +87,7 @@ export class Command { return Err({ command: this, stack, error: 'Unknown option.' }); } - public displayHelp(stack?: Command[]) { + public getHelpMessage(stack?: Command[]) { const globalOptions = [ ...this.options.filter((o) => o.global), ...(stack?.flatMap((o) => o.options.filter((o) => o.global)) ?? []), @@ -148,6 +161,6 @@ export class Command { }); } - console.error(commandLineUsage(sections)); + return commandLineUsage(sections); } } diff --git a/tools/cli/src/index.ts b/tools/cli/src/index.ts index c55b9bcd..20496dac 100644 --- a/tools/cli/src/index.ts +++ b/tools/cli/src/index.ts @@ -1,22 +1,51 @@ +import commandLineArgs from 'command-line-args'; import { Command } from './commands/Command'; +import { LoggerOptions, createLogger } from './logger'; -const mainCommand: Command = new Command({ +export interface GlobalOptions extends LoggerOptions { + readonly help: boolean; +} + +const mainCommand = new Command({ name: '', -}).option({ - name: 'help', - type: Boolean, - alias: 'h', - global: true, - description: 'Displays this help message.', -}); +}) + .option({ + name: 'help', + type: Boolean, + alias: 'h', + global: true, + description: 'Displays this help message.', + }) + .option({ + name: 'verbose', + type: Boolean, + alias: 'v', + global: true, + multiple: true, + description: 'Verbosity level. -v prints info logs, -vv prints debug logs, -vvv prints ALL logs.', + }) + .option({ + name: 'quiet', + type: Boolean, + alias: 'q', + global: true, + description: 'Disables ALL logging messages.', + }) + .option({ + name: 'log-level', + type: String, + global: true, + description: 'Sets the logging level. Can be one of: quiet, error, warn, info, debug, verbose', + }); (async () => { const result = await mainCommand.run(process.argv); if (result.isOk()) { process.exit(result.data); } else { - console.error(`Error: ${result.data.error}`); - result.data.command.displayHelp(result.data.stack); + const loggerOptions = commandLineArgs(mainCommand.options, { partial: true }) as Partial; + const logger = createLogger(loggerOptions); + logger.error(result.data.error); process.exit(1); } })(); diff --git a/tools/cli/src/logger.ts b/tools/cli/src/logger.ts new file mode 100644 index 00000000..bf1246d2 --- /dev/null +++ b/tools/cli/src/logger.ts @@ -0,0 +1,112 @@ +import { LogLevel, Logger } from '@backtrace/sourcemap-tools'; +import { format } from 'util'; + +export interface LoggerOptions { + readonly verbose?: boolean[]; + readonly quiet?: boolean; + readonly 'log-level'?: CliLogLevel; +} + +export type CliLogLevel = LogLevel | 'output'; + +export class CliLogger implements Logger { + private readonly _levelMap: Record; + + constructor(public readonly level: CliLogLevel, public readonly silent?: boolean) { + this._levelMap = this.createLevelMap(level); + } + + public output(value: unknown | Error, ...args: unknown[]) { + return this.log('output', value, ...args); + } + + public error(value: unknown | Error, ...args: unknown[]) { + return this.log('error', value, ...args); + } + + public warn(value: unknown | Error, ...args: unknown[]) { + return this.log('warn', value, ...args); + } + + public info(value: unknown | Error, ...args: unknown[]) { + return this.log('info', value, ...args); + } + + public debug(value: unknown | Error, ...args: unknown[]) { + return this.log('debug', value, ...args); + } + + public trace(value: unknown | Error, ...args: unknown[]) { + return this.log('trace', value, ...args); + } + + public log(level: CliLogLevel, value: unknown | Error, ...args: unknown[]) { + const isOutput = level === 'output'; + + if (this.silent && !isOutput) { + return; + } + + if (!this._levelMap[level]) { + return; + } + + const logger = isOutput + ? (...args: Parameters) => console.log(...args) + : (...args: Parameters) => console.error(...args); + + const message: unknown[] = []; + if (!isOutput) { + message.push(`${level}:`); + } + + if (value instanceof Error) { + message.push(...args, value); + } else { + message.push(value, ...args); + } + + logger(format(...message)); + } + + private createLevelMap(level: CliLogLevel): Record { + const levelMap: Record = { + output: 0, + error: 1, + warn: 2, + info: 3, + debug: 4, + trace: 5, + }; + + return { + output: levelMap[level] >= levelMap['output'], + error: levelMap[level] >= levelMap['error'], + warn: levelMap[level] >= levelMap['warn'], + info: levelMap[level] >= levelMap['info'], + debug: levelMap[level] >= levelMap['debug'], + trace: levelMap[level] >= levelMap['trace'], + }; + } +} + +export function createLogger(options?: LoggerOptions) { + let level: CliLogLevel | undefined; + if (options?.['log-level']) { + level = options?.['log-level']; + } else if (options?.verbose) { + switch (options.verbose.length) { + case 1: + level = 'info'; + break; + case 2: + level = 'debug'; + break; + case 3: + level = 'trace'; + break; + } + } + + return new CliLogger(level ?? 'info', options?.quiet); +} From 4f17e1131588e311326c7e2f8d3857b076d22eb1 Mon Sep 17 00:00:00 2001 From: Sebastian Alex Date: Wed, 5 Jul 2023 11:36:43 +0000 Subject: [PATCH 05/15] cli: add reference to @backtrace/sourcemap-tools --- package-lock.json | 2 ++ tools/cli/package.json | 1 + 2 files changed, 3 insertions(+) diff --git a/package-lock.json b/package-lock.json index 973d4a21..5dc42a76 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11694,6 +11694,7 @@ "version": "0.0.1", "license": "MIT", "dependencies": { + "@backtrace/sourcemap-tools": "^0.0.1", "command-line-args": "^5.2.1", "command-line-usage": "^7.0.1" }, @@ -12171,6 +12172,7 @@ "@backtrace/javascript-cli": { "version": "file:tools/cli", "requires": { + "@backtrace/sourcemap-tools": "^0.0.1", "@types/command-line-args": "^5.2.0", "@types/command-line-usage": "^5.0.2", "command-line-args": "^5.2.1", diff --git a/tools/cli/package.json b/tools/cli/package.json index 15616d09..1d5d903c 100644 --- a/tools/cli/package.json +++ b/tools/cli/package.json @@ -37,6 +37,7 @@ }, "homepage": "https://github.com/backtrace-labs/backtrace-javascript#readme", "dependencies": { + "@backtrace/sourcemap-tools": "^0.0.1", "command-line-args": "^5.2.1", "command-line-usage": "^7.0.1" }, From ac3df9cf4528960fa782befe81dc4879564585c6 Mon Sep 17 00:00:00 2001 From: Sebastian Alex Date: Mon, 10 Jul 2023 13:21:57 +0000 Subject: [PATCH 06/15] cli: add common functions --- tools/cli/src/helpers/common.ts | 50 +++++++++++++++++++++++++++++++++ tools/cli/src/helpers/find.ts | 35 +++++++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 tools/cli/src/helpers/common.ts create mode 100644 tools/cli/src/helpers/find.ts diff --git a/tools/cli/src/helpers/common.ts b/tools/cli/src/helpers/common.ts new file mode 100644 index 00000000..89c68d9b --- /dev/null +++ b/tools/cli/src/helpers/common.ts @@ -0,0 +1,50 @@ +import { Err, Ok, Result, ResultPromise } from '@backtrace/sourcemap-tools'; +import fs from 'fs'; + +export type ContentFile = readonly [content: string, path: string]; + +export async function readFile(file: string): ResultPromise { + try { + return Ok(await fs.promises.readFile(file, 'utf-8')); + } catch (err) { + return Err(`failed to read file: ${err instanceof Error ? err.message : 'unknown error'}`); + } +} + +export async function writeFile(file: ContentFile) { + const [content, path] = file; + try { + await fs.promises.writeFile(path, content); + return Ok(file); + } catch (err) { + return Err(`failed to write file: ${err instanceof Error ? err.message : 'unknown error'}`); + } +} + +export function parseJSON(content: string): Result { + try { + return Ok(JSON.parse(content)); + } catch (err) { + return Err(`failed to parse content: ${err instanceof Error ? err.message : 'unknown error'}`); + } +} + +export function pass(t: T): T { + return t; +} + +export function passOk(t: T): Result { + return Ok(t); +} + +export function failIfEmpty(error: E) { + return function failIfEmpty(t: T[]): Result { + return t.length ? Ok(t) : Err(error); + }; +} + +export function map(fn: (t: T) => B) { + return function map(t: T[]) { + return t.map(fn); + }; +} diff --git a/tools/cli/src/helpers/find.ts b/tools/cli/src/helpers/find.ts new file mode 100644 index 00000000..2ae5b2ad --- /dev/null +++ b/tools/cli/src/helpers/find.ts @@ -0,0 +1,35 @@ +import { Err, FileFinder, Ok, ResultPromise } from '@backtrace/sourcemap-tools'; +import fs from 'fs'; +import path from 'path'; + +export async function find(regex: RegExp, ...paths: string[]): ResultPromise { + const finder = new FileFinder(); + const results = new Map(); + for (const findPath of paths) { + const stat = await fs.promises.stat(findPath); + if (!stat.isDirectory()) { + if (!findPath.match(regex)) { + return Err(`${findPath} does not match regex: ${regex}`); + } + const fullPath = path.resolve(findPath); + if (!results.has(fullPath)) { + results.set(fullPath, findPath); + } + continue; + } + + const findResult = await finder.find(findPath, { match: regex, recursive: true }); + if (findResult.isErr()) { + return findResult; + } + + for (const result of findResult.data) { + const fullPath = path.resolve(result); + if (!results.has(fullPath)) { + results.set(fullPath, result); + } + } + } + + return Ok([...results.values()]); +} From c0ae4da52ed0031ce5e334affd5a4547351df7cc Mon Sep 17 00:00:00 2001 From: Sebastian Alex Date: Mon, 10 Jul 2023 13:22:11 +0000 Subject: [PATCH 07/15] cli: add process command --- tools/cli/src/index.ts | 2 + tools/cli/src/sourcemaps/process.ts | 115 ++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 tools/cli/src/sourcemaps/process.ts diff --git a/tools/cli/src/index.ts b/tools/cli/src/index.ts index 20496dac..acb1e98a 100644 --- a/tools/cli/src/index.ts +++ b/tools/cli/src/index.ts @@ -1,6 +1,7 @@ import commandLineArgs from 'command-line-args'; import { Command } from './commands/Command'; import { LoggerOptions, createLogger } from './logger'; +import { processCmd } from './sourcemaps/process'; export interface GlobalOptions extends LoggerOptions { readonly help: boolean; @@ -9,6 +10,7 @@ export interface GlobalOptions extends LoggerOptions { const mainCommand = new Command({ name: '', }) + .subcommand(processCmd) .option({ name: 'help', type: Boolean, diff --git a/tools/cli/src/sourcemaps/process.ts b/tools/cli/src/sourcemaps/process.ts new file mode 100644 index 00000000..207fc890 --- /dev/null +++ b/tools/cli/src/sourcemaps/process.ts @@ -0,0 +1,115 @@ +import { + AsyncResult, + DebugIdGenerator, + Err, + ProcessResultWithPaths, + Result, + SourceProcessor, + flatMap, +} from '@backtrace/sourcemap-tools'; +import { GlobalOptions } from '..'; +import { Command } from '../commands/Command'; +import { failIfEmpty, passOk, writeFile } from '../helpers/common'; +import { find } from '../helpers/find'; +import { CliLogger, createLogger } from '../logger'; + +interface ProcessOptions extends GlobalOptions { + readonly path: string[]; + readonly 'dry-run': boolean; + readonly force: boolean; + readonly 'pass-with-no-files': boolean; +} + +export const processCmd = new Command({ + name: 'process', + description: 'Processing source and sourcemap files', +}) + .option({ + name: 'path', + description: 'Path to sourcemap files or directories containing sourcemaps to upload.', + defaultOption: true, + defaultValue: process.cwd(), + multiple: true, + alias: 'p', + }) + .option({ + name: 'dry-run', + alias: 'n', + type: Boolean, + description: 'Does not modify the files at the end.', + defaultValue: false, + }) + .option({ + name: 'force', + alias: 'f', + type: Boolean, + description: 'Processes files even if already processed.', + defaultValue: false, + }) + .option({ + name: 'pass-with-no-files', + type: Boolean, + description: 'Exits with zero exit code if no files for processing are found.', + }) + .execute(function (opts, stack) { + const logger = createLogger(opts); + const sourceProcessor = new SourceProcessor(new DebugIdGenerator()); + logger.trace(`resolved options: \n${JSON.stringify(opts, null, ' ')}`); + + const searchPaths = opts.path; + if (!searchPaths) { + logger.info(this.getHelpMessage(stack)); + return Err('path must be specified'); + } + + return AsyncResult.equip(find(/\.(c|m)?jsx?$/, ...searchPaths)) + .then(opts.force ? passOk : filterUnprocessedFiles(sourceProcessor)) + .then(opts['pass-with-no-files'] ? passOk : failIfEmpty('no files for processing found')) + .then(processFiles(sourceProcessor)) + .then(opts['dry-run'] ? passOk : writeResults) + .then(output(logger)) + .then(() => 0).inner; + }); + +function filterUnprocessedFiles(sourceProcessor: SourceProcessor) { + return async function filterUnprocessedFiles(files: string[]): Promise> { + return flatMap( + await Promise.all( + files.map( + (file) => + AsyncResult.equip(sourceProcessor.isSourceFileProcessed(file)).then( + (result) => [file, result] as const, + ).inner, + ), + ), + ).map((results) => results.filter(([, result]) => !result).map(([file]) => file)); + }; +} + +function processFiles(sourceProcessor: SourceProcessor) { + return async function processFiles(pathsToProcess: string[]) { + return flatMap( + await Promise.all(pathsToProcess.map((file) => sourceProcessor.processSourceAndSourceMapFiles(file))), + ); + }; +} + +async function writeResults(results: ProcessResultWithPaths[]) { + return flatMap(await Promise.all(results.map(writeResult))); +} + +function writeResult(result: ProcessResultWithPaths) { + return AsyncResult.equip(writeFile([result.source, result.sourcePath])) + .then(() => writeFile([JSON.stringify(result.sourceMap), result.sourceMapPath])) + .then(() => result).inner; +} + +function output(logger: CliLogger) { + return function output(files: ProcessResultWithPaths[]) { + for (const { sourcePath } of files) { + logger.output(sourcePath); + } + + return files; + }; +} From b42befc5e8529eefe3fc61da34e356c861656368 Mon Sep 17 00:00:00 2001 From: Sebastian Alex Date: Wed, 5 Jul 2023 11:37:08 +0000 Subject: [PATCH 08/15] cli: add upload command --- tools/cli/src/index.ts | 2 + tools/cli/src/sourcemaps/upload.ts | 150 +++++++++++++++++++++++++++++ 2 files changed, 152 insertions(+) create mode 100644 tools/cli/src/sourcemaps/upload.ts diff --git a/tools/cli/src/index.ts b/tools/cli/src/index.ts index acb1e98a..bf07133b 100644 --- a/tools/cli/src/index.ts +++ b/tools/cli/src/index.ts @@ -2,6 +2,7 @@ import commandLineArgs from 'command-line-args'; import { Command } from './commands/Command'; import { LoggerOptions, createLogger } from './logger'; import { processCmd } from './sourcemaps/process'; +import { uploadCmd } from './sourcemaps/upload'; export interface GlobalOptions extends LoggerOptions { readonly help: boolean; @@ -11,6 +12,7 @@ const mainCommand = new Command({ name: '', }) .subcommand(processCmd) + .subcommand(uploadCmd) .option({ name: 'help', type: Boolean, diff --git a/tools/cli/src/sourcemaps/upload.ts b/tools/cli/src/sourcemaps/upload.ts new file mode 100644 index 00000000..1b836e3d --- /dev/null +++ b/tools/cli/src/sourcemaps/upload.ts @@ -0,0 +1,150 @@ +import { + AsyncResult, + DebugIdGenerator, + Err, + Ok, + Result, + ResultPromise, + SourceProcessor, + SymbolUploader, + UploadResult, + ZipArchive, + flatMap, +} from '@backtrace/sourcemap-tools'; +import path from 'path'; +import { Readable } from 'stream'; +import { GlobalOptions } from '..'; +import { Command } from '../commands/Command'; +import { failIfEmpty, passOk } from '../helpers/common'; +import { find } from '../helpers/find'; +import { CliLogger, createLogger } from '../logger'; + +interface UploadOptions extends GlobalOptions { + readonly url: string; + readonly path: string[]; + readonly 'no-sources': string; + readonly insecure: boolean; + readonly 'dry-run': boolean; + readonly force: boolean; + readonly 'pass-with-no-files': boolean; +} + +export const uploadCmd = new Command({ + name: 'upload', + description: 'Uploading of sourcemaps to Backtrace', +}) + .option({ + name: 'url', + type: String, + description: 'URL to upload to. You can use also BACKTRACE_JS_UPLOAD_URL env variable.', + alias: 'u', + defaultValue: process.env.BACKTRACE_JS_UPLOAD_URL, + }) + .option({ + name: 'path', + type: String, + description: 'Path to sourcemap files or directories containing sourcemaps to upload.', + defaultOption: true, + defaultValue: process.cwd(), + multiple: true, + alias: 'p', + }) + .option({ + name: 'no-sources', + type: Boolean, + description: 'Uploads the sourcemaps without "sourcesContent" key.', + defaultValue: false, + }) + .option({ + name: 'insecure', + alias: 'k', + type: Boolean, + description: 'Disables HTTPS certificate checking.', + defaultValue: false, + }) + .option({ + name: 'dry-run', + alias: 'n', + type: Boolean, + description: 'Does not upload the files at the end.', + defaultValue: false, + }) + .option({ + name: 'force', + alias: 'f', + type: Boolean, + description: 'Upload files even if not processed.', + defaultValue: false, + }) + .option({ + name: 'pass-with-no-files', + type: Boolean, + description: 'Exits with zero exit code if no files for uploading are found.', + }) + .execute(function (opts, stack) { + const logger = createLogger(opts); + const sourceProcessor = new SourceProcessor(new DebugIdGenerator()); + logger.trace(`resolved options: \n${JSON.stringify(opts, null, ' ')}`); + + const searchPaths = opts.path; + if (!searchPaths) { + logger.info(this.getHelpMessage(stack)); + return Err('path must be specified'); + } + + const uploadUrl = opts.url; + if (!uploadUrl) { + logger.info(this.getHelpMessage(stack)); + return Err('upload URL is required.'); + } + + const uploader = new SymbolUploader(uploadUrl, { ignoreSsl: opts.insecure ?? false }); + + return AsyncResult.equip(find(/\.(c|m)?jsx?\.map$/, ...searchPaths)) + .then(opts.force ? passOk : filterProcessedFiles(sourceProcessor)) + .then(opts['pass-with-no-files'] ? passOk : failIfEmpty('no files for uploading found')) + .then(createArchiveForUpload) + .then((archive) => (opts['dry-run'] ? Ok(null) : uploadArchive(uploader)(archive))) + .then(output(logger)) + .then(() => 0).inner; + }); + +function filterProcessedFiles(sourceProcessor: SourceProcessor) { + return async function filterProcessedFiles(files: string[]): Promise> { + return flatMap( + await Promise.all( + files.map( + (file) => + AsyncResult.equip(sourceProcessor.isSourceMapFileProcessed(file)).then( + (result) => [file, result] as const, + ).inner, + ), + ), + ).map((results) => results.filter(([, result]) => result).map(([file]) => file)); + }; +} + +async function createArchiveForUpload(pathsToArchive: string[]): ResultPromise { + const archive = new ZipArchive(); + + for (const filePath of pathsToArchive) { + const fileName = path.basename(filePath); + archive.append(fileName, filePath); + } + + await archive.finalize(); + return Ok(archive); +} + +function uploadArchive(symbolUploader: SymbolUploader) { + return async function uploadArchive(stream: Readable): ResultPromise { + return await symbolUploader.uploadSymbol(stream); + }; +} + +function output(logger: CliLogger) { + return function output(result: UploadResult | null) { + logger.output(result?.rxid ?? ''); + return result; + }; +} From 185fd52ae0731d5d6616e0390096a90ab982caf5 Mon Sep 17 00:00:00 2001 From: Sebastian Alex Date: Thu, 6 Jul 2023 11:35:38 +0000 Subject: [PATCH 09/15] cli: add addSources command --- tools/cli/src/index.ts | 2 + tools/cli/src/sourcemaps/add-sources.ts | 118 ++++++++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 tools/cli/src/sourcemaps/add-sources.ts diff --git a/tools/cli/src/index.ts b/tools/cli/src/index.ts index bf07133b..165a937a 100644 --- a/tools/cli/src/index.ts +++ b/tools/cli/src/index.ts @@ -1,6 +1,7 @@ import commandLineArgs from 'command-line-args'; import { Command } from './commands/Command'; import { LoggerOptions, createLogger } from './logger'; +import { addSourcesCmd } from './sourcemaps/add-sources'; import { processCmd } from './sourcemaps/process'; import { uploadCmd } from './sourcemaps/upload'; @@ -13,6 +14,7 @@ const mainCommand = new Command({ }) .subcommand(processCmd) .subcommand(uploadCmd) + .subcommand(addSourcesCmd) .option({ name: 'help', type: Boolean, diff --git a/tools/cli/src/sourcemaps/add-sources.ts b/tools/cli/src/sourcemaps/add-sources.ts new file mode 100644 index 00000000..b560fc56 --- /dev/null +++ b/tools/cli/src/sourcemaps/add-sources.ts @@ -0,0 +1,118 @@ +import { AsyncResult, DebugIdGenerator, Err, SourceProcessor, flatMap } from '@backtrace/sourcemap-tools'; +import { GlobalOptions } from '..'; +import { Command } from '../commands/Command'; +import { ContentFile, failIfEmpty, map, parseJSON, pass, passOk, readFile, writeFile } from '../helpers/common'; +import { find } from '../helpers/find'; +import { CliLogger, createLogger } from '../logger'; + +interface AddSourcesOptions extends GlobalOptions { + readonly path: string[]; + readonly 'dry-run': boolean; + readonly force: boolean; + readonly skipFailing: boolean; + readonly 'pass-with-no-files': boolean; +} + +type ObjectFile = readonly [object, string]; + +export const addSourcesCmd = new Command({ + name: 'add-sources', + description: 'Adds sources to sourcemap files', +}) + .option({ + name: 'path', + description: 'Path to sourcemap files to append sources to.', + defaultOption: true, + defaultValue: process.cwd(), + multiple: true, + alias: 'p', + }) + .option({ + name: 'dry-run', + alias: 'n', + type: Boolean, + description: 'Does not modify the files at the end.', + defaultValue: false, + }) + .option({ + name: 'force', + alias: 'f', + type: Boolean, + description: 'Processes files even if sourcesContent is not empty. Will overwrite existing sources.', + defaultValue: false, + }) + .option({ + name: 'pass-with-no-files', + type: Boolean, + description: 'Exits with zero exit code if no sourcemaps are found.', + }) + .execute(function (opts, stack) { + const logger = createLogger(opts); + const sourceProcessor = new SourceProcessor(new DebugIdGenerator()); + logger.trace(`resolved options: \n${JSON.stringify(opts, null, ' ')}`); + + const searchPaths = opts.path; + if (!searchPaths) { + logger.info(this.getHelpMessage(stack)); + return Err('path must be specified'); + } + + return AsyncResult.equip(find(/\.(c|m)?jsx?\.map$/, ...searchPaths)) + .then(readFiles) + .then(loadFiles) + .then(opts.force ? pass : filterFiles(sourceProcessor)) + .then(opts['pass-with-no-files'] ? passOk : failIfEmpty('no valid sourcemaps found')) + .then(map(addSource(sourceProcessor))) + .then(opts['dry-run'] ? passOk : writeSourceMaps) + .then(output(logger)) + .then(() => 0).inner; + }); + +async function readFiles(paths: string[]) { + return Promise.all( + paths.map((f) => AsyncResult.equip(readFile(f)).then((content) => [content, f] as ContentFile).inner), + ); +} + +function loadFiles(files: ContentFile[]) { + return files.map(([content, path]) => parseJSON(content).map((c) => [c, path] as ObjectFile)); +} + +function filterFiles(sourceProcessor: SourceProcessor) { + return function filterFiles(files: ObjectFile[]) { + return files.filter(filterSourceMapWithoutSource(sourceProcessor)); + }; +} + +function filterSourceMapWithoutSource(sourceProcessor: SourceProcessor) { + return function filterSourceMapWithoutSource(sourceMap: ObjectFile): boolean { + return !sourceProcessor.doesSourceMapHaveSources(sourceMap[0] as never); + }; +} + +function addSource(sourceProcessor: SourceProcessor) { + return function addSource([sourceMapObj, sourceMapPath]: ObjectFile) { + return AsyncResult.equip(sourceProcessor.addSourcesToSourceMap(sourceMapObj as never, sourceMapPath)).then( + (newSourceMap) => [newSourceMap, sourceMapPath] as const, + ).inner; + }; +} + +async function writeSourceMaps(file: ObjectFile[]) { + return flatMap(await Promise.all(file.map(writeSourceMap))); +} + +function writeSourceMap(file: ObjectFile) { + const [sourceMapObj, sourceMapPath] = file; + return AsyncResult.equip(writeFile([JSON.stringify(sourceMapObj), sourceMapPath])).then(() => file).inner; +} + +function output(logger: CliLogger) { + return function output(files: ObjectFile[]) { + for (const [, file] of files) { + logger.output(file); + } + + return files; + }; +} From ef539e436cd2741122208a80e35d88a98467a24e Mon Sep 17 00:00:00 2001 From: Sebastian Alex Date: Mon, 10 Jul 2023 15:25:17 +0000 Subject: [PATCH 10/15] cli: add archive output feature --- tools/cli/src/helpers/common.ts | 19 +++++++++++++++++ tools/cli/src/sourcemaps/upload.ts | 34 +++++++++++++++++++++++++----- 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/tools/cli/src/helpers/common.ts b/tools/cli/src/helpers/common.ts index 89c68d9b..687da6c9 100644 --- a/tools/cli/src/helpers/common.ts +++ b/tools/cli/src/helpers/common.ts @@ -1,7 +1,9 @@ import { Err, Ok, Result, ResultPromise } from '@backtrace/sourcemap-tools'; import fs from 'fs'; +import { Readable } from 'stream'; export type ContentFile = readonly [content: string, path: string]; +export type StreamFile = readonly [stream: Readable, path: string]; export async function readFile(file: string): ResultPromise { try { @@ -21,6 +23,23 @@ export async function writeFile(file: ContentFile) { } } +export async function writeStream(file: StreamFile) { + const [stream, path] = file; + try { + const output = fs.createWriteStream(path); + stream.pipe(output); + return new Promise>((resolve) => { + output.on('error', (err) => { + resolve(Err(`failed to write file: ${err.message}`)); + }); + + output.on('finish', () => resolve(Ok(file))); + }); + } catch (err) { + return Err(`failed to write file: ${err instanceof Error ? err.message : 'unknown error'}`); + } +} + export function parseJSON(content: string): Result { try { return Ok(JSON.parse(content)); diff --git a/tools/cli/src/sourcemaps/upload.ts b/tools/cli/src/sourcemaps/upload.ts index 1b836e3d..00f6169b 100644 --- a/tools/cli/src/sourcemaps/upload.ts +++ b/tools/cli/src/sourcemaps/upload.ts @@ -11,11 +11,12 @@ import { ZipArchive, flatMap, } from '@backtrace/sourcemap-tools'; +import fs from 'fs'; import path from 'path'; import { Readable } from 'stream'; import { GlobalOptions } from '..'; import { Command } from '../commands/Command'; -import { failIfEmpty, passOk } from '../helpers/common'; +import { failIfEmpty, passOk, writeStream } from '../helpers/common'; import { find } from '../helpers/find'; import { CliLogger, createLogger } from '../logger'; @@ -27,6 +28,7 @@ interface UploadOptions extends GlobalOptions { readonly 'dry-run': boolean; readonly force: boolean; readonly 'pass-with-no-files': boolean; + readonly output: string; } export const uploadCmd = new Command({ @@ -81,6 +83,12 @@ export const uploadCmd = new Command({ type: Boolean, description: 'Exits with zero exit code if no files for uploading are found.', }) + .option({ + name: 'output', + alias: 'o', + description: 'If set, archive with sourcemaps will be outputted to this path instead of being uploaded.', + type: String, + }) .execute(function (opts, stack) { const logger = createLogger(opts); const sourceProcessor = new SourceProcessor(new DebugIdGenerator()); @@ -92,19 +100,28 @@ export const uploadCmd = new Command({ return Err('path must be specified'); } + const outputPath = opts.output; const uploadUrl = opts.url; - if (!uploadUrl) { + if (!outputPath && !uploadUrl) { logger.info(this.getHelpMessage(stack)); return Err('upload URL is required.'); } - const uploader = new SymbolUploader(uploadUrl, { ignoreSsl: opts.insecure ?? false }); + const processArchive = outputPath + ? saveArchive(outputPath) + : uploadUrl + ? uploadArchive(new SymbolUploader(uploadUrl, { ignoreSsl: opts.insecure ?? false })) + : undefined; + + if (!processArchive) { + throw new Error('processArchive function should be defined'); + } return AsyncResult.equip(find(/\.(c|m)?jsx?\.map$/, ...searchPaths)) .then(opts.force ? passOk : filterProcessedFiles(sourceProcessor)) .then(opts['pass-with-no-files'] ? passOk : failIfEmpty('no files for uploading found')) .then(createArchiveForUpload) - .then((archive) => (opts['dry-run'] ? Ok(null) : uploadArchive(uploader)(archive))) + .then((archive) => (opts['dry-run'] ? Ok(null) : processArchive(archive))) .then(output(logger)) .then(() => 0).inner; }); @@ -129,7 +146,8 @@ async function createArchiveForUpload(pathsToArchive: string[]): ResultPromise { + return AsyncResult.equip(writeStream([stream, filePath])).then(([, rxid]) => ({ rxid })).inner; + }; +} + function output(logger: CliLogger) { return function output(result: UploadResult | null) { logger.output(result?.rxid ?? ''); From c18dfc1189f684d38c061794e27e1b457567d6d0 Mon Sep 17 00:00:00 2001 From: Sebastian Alex Date: Tue, 18 Jul 2023 08:30:40 +0000 Subject: [PATCH 11/15] cli: change verbosity levels --- tools/cli/src/index.ts | 4 ++-- tools/cli/src/logger.ts | 5 +---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/tools/cli/src/index.ts b/tools/cli/src/index.ts index 165a937a..deaa2a52 100644 --- a/tools/cli/src/index.ts +++ b/tools/cli/src/index.ts @@ -28,7 +28,7 @@ const mainCommand = new Command({ alias: 'v', global: true, multiple: true, - description: 'Verbosity level. -v prints info logs, -vv prints debug logs, -vvv prints ALL logs.', + description: 'Verbosity level. -v prints debug logs, -vv prints ALL logs.', }) .option({ name: 'quiet', @@ -41,7 +41,7 @@ const mainCommand = new Command({ name: 'log-level', type: String, global: true, - description: 'Sets the logging level. Can be one of: quiet, error, warn, info, debug, verbose', + description: 'Sets the logging level. Can be one of: quiet, error, warn, info, debug, verbose. Default: info', }); (async () => { diff --git a/tools/cli/src/logger.ts b/tools/cli/src/logger.ts index bf1246d2..7b4ce5ca 100644 --- a/tools/cli/src/logger.ts +++ b/tools/cli/src/logger.ts @@ -97,12 +97,9 @@ export function createLogger(options?: LoggerOptions) { } else if (options?.verbose) { switch (options.verbose.length) { case 1: - level = 'info'; - break; - case 2: level = 'debug'; break; - case 3: + case 2: level = 'trace'; break; } From d47bc177993b893f1e2c3ce6749a3616ed123c96 Mon Sep 17 00:00:00 2001 From: Sebastian Alex Date: Tue, 18 Jul 2023 08:31:09 +0000 Subject: [PATCH 12/15] cli: add doc to find --- tools/cli/src/helpers/find.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/cli/src/helpers/find.ts b/tools/cli/src/helpers/find.ts index 2ae5b2ad..02b25cc4 100644 --- a/tools/cli/src/helpers/find.ts +++ b/tools/cli/src/helpers/find.ts @@ -2,6 +2,12 @@ import { Err, FileFinder, Ok, ResultPromise } from '@backtrace/sourcemap-tools'; import fs from 'fs'; import path from 'path'; +/** + * Returns files found in directories matching `regex`. If path is a file, it is returned if it matches `regex`. + * @param regex Regular expression pattern to match. + * @param paths Paths to search in. + * @returns Result with file paths. + */ export async function find(regex: RegExp, ...paths: string[]): ResultPromise { const finder = new FileFinder(); const results = new Map(); From 6cffee7c1dd0cee56c7a23312ebc3593f03e530c Mon Sep 17 00:00:00 2001 From: Sebastian Alex Date: Tue, 18 Jul 2023 08:31:23 +0000 Subject: [PATCH 13/15] cli: extract 'backtrace' command name to a const --- tools/cli/src/commands/Command.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/cli/src/commands/Command.ts b/tools/cli/src/commands/Command.ts index 234fa007..2a1ada72 100644 --- a/tools/cli/src/commands/Command.ts +++ b/tools/cli/src/commands/Command.ts @@ -5,6 +5,8 @@ import { LoggerOptions, createLogger } from '../logger'; import { CommandError } from '../models/CommandError'; import { ExtendedOptionDefinition } from '../models/OptionDefinition'; +const CLI_COMMAND = 'backtrace'; + export class Command { public readonly subcommands: Command[] = []; public readonly options: ExtendedOptionDefinition[] = []; @@ -95,7 +97,7 @@ export class Command { const nonGlobalOptions = this.options.filter((o) => !o.global); - let cmd = 'backtrace'; + let cmd = CLI_COMMAND; const stackCmd = `${ [...(stack ?? []), this] .map((s) => s.definition.name) From 04ce4488ae0e5e93039415474d08e7364433d0e4 Mon Sep 17 00:00:00 2001 From: Sebastian Alex Date: Mon, 17 Jul 2023 11:11:28 +0000 Subject: [PATCH 14/15] cli: fix file collisions in uploaded zip archive --- tools/cli/src/sourcemaps/upload.ts | 24 +++++++++++++-- tools/sourcemap-tools/src/SourceProcessor.ts | 32 +++++++++++++++++++- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/tools/cli/src/sourcemaps/upload.ts b/tools/cli/src/sourcemaps/upload.ts index 00f6169b..23a586e6 100644 --- a/tools/cli/src/sourcemaps/upload.ts +++ b/tools/cli/src/sourcemaps/upload.ts @@ -119,6 +119,7 @@ export const uploadCmd = new Command({ return AsyncResult.equip(find(/\.(c|m)?jsx?\.map$/, ...searchPaths)) .then(opts.force ? passOk : filterProcessedFiles(sourceProcessor)) + .then(readDebugIds(sourceProcessor)) .then(opts['pass-with-no-files'] ? passOk : failIfEmpty('no files for uploading found')) .then(createArchiveForUpload) .then((archive) => (opts['dry-run'] ? Ok(null) : processArchive(archive))) @@ -141,13 +142,30 @@ function filterProcessedFiles(sourceProcessor: SourceProcessor) { }; } -async function createArchiveForUpload(pathsToArchive: string[]): ResultPromise { +function readDebugIds(sourceProcessor: SourceProcessor) { + return async function readDebugIds(files: string[]): Promise> { + return flatMap( + await Promise.all( + files.map( + (file) => + AsyncResult.equip(sourceProcessor.getSourceMapFileDebugId(file)).then( + (result) => [file, result] as const, + ).inner, + ), + ), + ); + }; +} + +async function createArchiveForUpload( + pathsToArchive: (readonly [string, string])[], +): ResultPromise { const archive = new ZipArchive(); - for (const filePath of pathsToArchive) { + for (const [filePath, debugId] of pathsToArchive) { const fileName = path.basename(filePath); const readStream = fs.createReadStream(filePath); - archive.append(fileName, readStream); + archive.append(`${debugId}-${fileName}`, readStream); } await archive.finalize(); diff --git a/tools/sourcemap-tools/src/SourceProcessor.ts b/tools/sourcemap-tools/src/SourceProcessor.ts index 2d594fcc..b85183bd 100644 --- a/tools/sourcemap-tools/src/SourceProcessor.ts +++ b/tools/sourcemap-tools/src/SourceProcessor.ts @@ -4,7 +4,7 @@ import { BasicSourceMapConsumer, Position, RawSourceMap, SourceMapConsumer, Sour import { DebugIdGenerator } from './DebugIdGenerator'; import { stringToUuid } from './helpers/stringToUuid'; import { ResultPromise } from './models/AsyncResult'; -import { Err, Ok } from './models/Result'; +import { Err, Ok, Result } from './models/Result'; export interface ProcessResult { readonly debugId: string; @@ -53,6 +53,36 @@ export class SourceProcessor { return Ok(this.isSourceMapProcessed(sourcemap)); } + public getSourceMapDebugId(sourceMap: RawSourceMap): Result { + const debugId = this._debugIdGenerator.getSourceMapDebugId(sourceMap); + if (!debugId) { + return Err('sourcemap does not have a debug ID'); + } + + return Ok(debugId); + } + + public async getSourceMapFileDebugId(sourceMapPath: string): ResultPromise { + const readResult = await this.readFile(sourceMapPath); + if (readResult.isErr()) { + return readResult; + } + + let sourcemap: RawSourceMap; + try { + sourcemap = JSON.parse(readResult.data) as RawSourceMap; + } catch (err) { + return Err('failed to parse sourcemap JSON'); + } + + const debugId = this._debugIdGenerator.getSourceMapDebugId(sourcemap); + if (!debugId) { + return Err('sourcemap does not have a debug ID'); + } + + return Ok(debugId); + } + /** * Adds required snippets and comments to source, and modifies sourcemap to include debug ID. * @param source Source content. From 8180cfb10739246395b62e6ce17cc43cc0a20921 Mon Sep 17 00:00:00 2001 From: Sebastian Alex Date: Tue, 18 Jul 2023 10:06:31 +0000 Subject: [PATCH 15/15] cli: change default Command generic param to object --- tools/cli/src/commands/Command.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cli/src/commands/Command.ts b/tools/cli/src/commands/Command.ts index 2a1ada72..8f63b743 100644 --- a/tools/cli/src/commands/Command.ts +++ b/tools/cli/src/commands/Command.ts @@ -7,7 +7,7 @@ import { ExtendedOptionDefinition } from '../models/OptionDefinition'; const CLI_COMMAND = 'backtrace'; -export class Command { +export class Command { public readonly subcommands: Command[] = []; public readonly options: ExtendedOptionDefinition[] = []; public readonly helpSections: Section[] = [];