├── .editorconfig ├── .eslintignore ├── .eslintrc.yml ├── .github ├── CODEOWNERS ├── CODE_OF_CONDUCT.md ├── labeler.yml └── workflows │ ├── deploy.yml │ ├── label.yml │ └── nodejs.yml ├── .gitignore ├── .markdownlint.yml ├── .mocharc.js ├── .rtkrc.js ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── babel.config.json ├── globals.d.ts ├── jsconfig.json ├── lerna.json ├── lint-staged.config.js ├── netlify.toml ├── package-lock.json ├── package.json ├── packages ├── README.md ├── cli │ ├── .eslintignore │ ├── CHANGELOG.md │ ├── LICENSE.md │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── commands │ │ │ ├── common.js │ │ │ ├── diff.js │ │ │ ├── index.js │ │ │ ├── inspect.js │ │ │ ├── list-rules.js │ │ │ ├── redact.js │ │ │ └── transform.js │ │ ├── console-utils.js │ │ └── index.js │ └── test │ │ ├── common.spec.js │ │ └── e2e │ │ ├── cli-helper.js │ │ ├── common.spec.js │ │ ├── diff.spec.js │ │ ├── inspect.spec.js │ │ ├── list-rules.spec.js │ │ └── transform.spec.js ├── common │ ├── .eslintignore │ ├── CHANGELOG.md │ ├── LICENSE.md │ ├── README.md │ ├── diagnostic-report-v2.schema.json │ ├── diagnostic-report.d.ts │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── config.js │ │ ├── configs │ │ │ └── recommended.js │ │ ├── constants.js │ │ ├── debug.js │ │ ├── error.js │ │ ├── index.js │ │ ├── observable.js │ │ ├── redact.js │ │ ├── report.js │ │ ├── symbols.js │ │ └── util.js │ └── test │ │ ├── config.spec.js │ │ ├── fixture │ │ ├── config │ │ │ ├── .rtkrc.js │ │ │ └── custom.config.js │ │ ├── diff │ │ │ └── report-001-002.json │ │ └── reports │ │ │ ├── report-001.json │ │ │ ├── report-002-library-mismatch.json │ │ │ ├── report-003-long-timeout.json │ │ │ ├── report-004-long-timeout-unref.json │ │ │ ├── report-005-secrets.json │ │ │ ├── report-006-cpu-usage.json │ │ │ ├── report-007-long-timeout-expired.json │ │ │ ├── report-008-cpu-usage-no-cpus.json │ │ │ ├── report-009-cpu-usage-multicore.json │ │ │ ├── report-010-win32.json │ │ │ └── report-011-missing-prop.json │ │ ├── redact.spec.js │ │ ├── report.spec.js │ │ ├── setup.js │ │ └── sinon-rxjs.js ├── core │ ├── .eslintignore │ ├── CHANGELOG.md │ ├── LICENSE.md │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── index.js │ │ └── observable.js │ └── test │ │ ├── fixture │ │ └── plugins │ │ │ └── baz │ │ │ ├── bar.js │ │ │ ├── foo.js │ │ │ └── index.js │ │ ├── index.spec.js │ │ └── observable.spec.js ├── diff │ ├── .eslintignore │ ├── CHANGELOG.md │ ├── LICENSE.md │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── src │ │ └── index.js │ └── test │ │ └── index.spec.js ├── docs │ ├── CHANGELOG.md │ ├── LICENSE.md │ ├── README.md │ ├── gatsby-browser.js │ ├── gatsby-config.js │ ├── gatsby-node.js │ ├── package-lock.json │ ├── package.json │ └── src │ │ ├── api.mdx │ │ ├── components │ │ ├── index.js │ │ ├── inline-code.js │ │ └── metadata.js │ │ ├── data │ │ └── nav-items.yaml │ │ ├── gatsby-theme-carbon │ │ ├── components │ │ │ ├── Code │ │ │ │ ├── Code.js │ │ │ │ ├── Code.module.scss │ │ │ │ ├── PathRow.js │ │ │ │ ├── Sidebar.js │ │ │ │ ├── index.js │ │ │ │ └── prismTheme.js │ │ │ ├── Footer.js │ │ │ ├── Header.js │ │ │ ├── InlineNotification │ │ │ │ └── InlineNotification.module.scss │ │ │ ├── Layout.js │ │ │ ├── LeftNav │ │ │ │ └── ResourceLinks.js │ │ │ ├── MDXProvider │ │ │ │ └── defaultComponents.js │ │ │ ├── PageHeader │ │ │ │ └── PageHeader.module.scss │ │ │ └── markdown │ │ │ │ └── H4.js │ │ ├── templates │ │ │ ├── Homepage.js │ │ │ └── Homepage.module.scss │ │ └── util │ │ │ └── hooks │ │ │ └── useMetadata.js │ │ ├── images │ │ └── report-json.png │ │ ├── pages │ │ ├── 404.js │ │ ├── api │ │ │ └── .gitkeep │ │ ├── cli │ │ │ ├── index.mdx │ │ │ └── index.module.scss │ │ ├── config │ │ │ └── index.mdx │ │ ├── index.mdx │ │ └── quick-start │ │ │ ├── diff-output.txt │ │ │ ├── index.mdx │ │ │ ├── index.module.scss │ │ │ ├── inspect-output-1.txt │ │ │ ├── inspect-output-2.txt │ │ │ ├── transform-output-1.txt │ │ │ ├── transform-output-2.txt │ │ │ ├── transform-output-3.txt │ │ │ └── transform-output-4.txt │ │ ├── styles │ │ └── index.scss │ │ └── util │ │ └── hooks │ │ ├── index.js │ │ └── use-text-file.js ├── fs │ ├── .eslintignore │ ├── CHANGELOG.md │ ├── LICENSE.md │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── constants.js │ │ ├── fs-config-loader.js │ │ ├── fs-report-loader.js │ │ └── index.js │ └── test │ │ ├── fixture │ │ └── rules │ │ │ ├── bar.js │ │ │ └── foo.js │ │ ├── fs-config-loader.spec.js │ │ └── fs-report-loader.spec.js ├── inspector │ ├── .eslintignore │ ├── CHANGELOG.md │ ├── LICENSE.md │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── ajv.js │ │ ├── index.js │ │ ├── message.js │ │ ├── rule-config.js │ │ ├── rule.js │ │ └── rules │ │ │ ├── cpu-usage.js │ │ │ ├── index.js │ │ │ ├── library-mismatch.js │ │ │ ├── long-timeout.js │ │ │ └── memory-usage.js │ └── test │ │ ├── index.spec.js │ │ ├── rule-config.spec.js │ │ ├── rule.spec.js │ │ └── rules │ │ ├── cpu-usage.spec.js │ │ ├── library-mismatch.spec.js │ │ ├── long-timeout.spec.js │ │ └── rules-helper.js ├── report-toolkit │ ├── .eslintignore │ ├── CHANGELOG.md │ ├── LICENSE.md │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── src │ │ └── index.js │ └── test │ │ └── index.spec.js └── transformers │ ├── CHANGELOG.md │ ├── LICENSE.md │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── src │ ├── csv.js │ ├── filter.js │ ├── index.js │ ├── json.js │ ├── newline.js │ ├── redact.js │ ├── stack-hash.js │ ├── table.js │ └── transformer.js │ └── test │ ├── csv.spec.js │ ├── json.spec.js │ ├── newline.spec.js │ ├── redact.spec.js │ └── stack-hash.spec.js ├── rollup.config.js ├── scripts ├── build-cli-output.js ├── modules.json ├── post-build-declarations.js └── typedoc-plugin-markdown-gatsby-theme │ ├── components │ └── breadcrumbs.js │ ├── helpers │ └── member-title.js │ ├── layouts │ └── default.hbs │ ├── partials │ ├── header.hbs │ ├── index.hbs │ ├── member.indexSignatures.hbs │ └── reflection.hbs │ ├── templates │ ├── index.hbs │ └── reflection.hbs │ └── theme.js ├── tsconfig.base.json ├── tsconfig.declarations.json └── tsconfig.docs.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.{md,mdx}] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | **/coverage/**/* 2 | **/dist/**/* 3 | **/node_modules/**/* 4 | packages/docs/public 5 | packages/docs/build 6 | **/*.log 7 | -------------------------------------------------------------------------------- /.eslintrc.yml: -------------------------------------------------------------------------------- 1 | 'extends': 2 | - 'semistandard' 3 | - 'plugin:prettier/recommended' 4 | - 'plugin:import/errors' 5 | - 'plugin:monorepo/recommended' 6 | - 'prettier/react' 7 | - 'plugin:react/recommended' 8 | - 'plugin:jsx-a11y/recommended' 9 | overrides: 10 | - files: 11 | - '.mocharc.js' 12 | - 'lint-staged.config.js' 13 | parserOptions: 14 | sourceType: 'script' 15 | - env: 16 | mocha: true 17 | files: 18 | - '**/test/**/*.spec.js' 19 | globals: 20 | expect: false 21 | proxyquire: false 22 | sinon: false 23 | rules: 24 | no-restricted-syntax: 25 | - 'error' 26 | - selector: "Program > ExpressionStatement > CallExpression[callee.name=describe] > Literal:not([raw=/^'@report-toolkit\\u002F\\S+?(:\\S+)*'/])" 27 | message: 'Top-level describe() must be of format "@report-toolkit/" or "@report-toolkit/:[:module...]"' 28 | monorepo/no-internal-import: 0 29 | - files: 30 | - 'packages/docs/**/*' 31 | rules: 32 | import/extensions: 0 33 | parser: 'babel-eslint' 34 | plugins: 35 | - 'react-hooks' 36 | root: true 37 | rules: 38 | import/exports-last: 'error' 39 | import/extensions: 40 | - 'error' 41 | - 'always' 42 | - 'ignorePackages': true 43 | import/order: 0 44 | no-restricted-syntax: 45 | - 'error' 46 | - selector: 'CallExpression[callee.name=Symbol] > Literal:not([value=/^report-toolkit-[a-z-]+$/])' 47 | message: 'Symbol() must be called with a kebab-case description beginning with "report-toolkit-"' 48 | react/prop-types: 0 49 | react/destructuring-assignment: 0 50 | react/no-access-state-in-setstate: 0 51 | standard/computed-property-even-spacing: 0 52 | strict: 53 | - 'error' 54 | - 'safe' 55 | settings: 56 | react: 57 | version: 'latest' 58 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @boneskull 2 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | ## Be friendly and patient 4 | 5 | We understand that everyone has different levels of experience or knowledge in many diverse fields, be it technical or 6 | non-technical in nature. We also have areas of knowledge we are eager to expand; we want to be a community where people 7 | can not only contribute, but feel comfortable to ask questions as well and learn along the way. If someone says something 8 | wrong, or says something accidentally offensive, respond with patience and try to keep it polite and civil. Remember that 9 | we all were newbies at one point. 10 | 11 | ## Be welcoming 12 | 13 | We strive to be a community that welcomes and supports people of all backgrounds and identities. This includes, but is not 14 | limited to, members of any race, ethnicity, culture, national origin, color, immigration status, social and economic class, 15 | educational level, sex, sexual orientation, gender identity and expression, age, size, family status, political belief, 16 | religion, and mental and physical ability. 17 | 18 | ## Be considerate 19 | 20 | Your work will be used by other people, and you in turn will depend on the work of others. Any decision you make will affect 21 | users and colleagues, and you should take those consequences into account when making decisions. Remember that we’re a world-wide 22 | community, so you might not be communicating in someone else’s primary language. 23 | 24 | ## Be respectful 25 | 26 | Not all of us will agree all the time, but disagreement is no excuse for poor behavior and poor manners. We might all 27 | experience some frustration now and then, but we cannot allow that frustration to turn into a personal attack. It’s important 28 | to remember that a community where people feel uncomfortable or threatened is not a productive one. Members of the JS Foundation 29 | community should be respectful when dealing with other members as well as with people outside the JS Foundation community. 30 | 31 | ## Be careful in the words that you choose 32 | 33 | We are a community of professionals, and we conduct ourselves professionally. Be kind to others. Do not insult or put 34 | down other participants. Harassment and other exclusionary behavior aren’t acceptable. This includes, but is not limited to: 35 | 36 | - Violent threats or language directed against another person. 37 | - Discriminatory jokes and language. 38 | - Posting sexually explicit or violent material. 39 | - Posting (or threatening to post) other people’s personally identifying information (“doxing”). 40 | - Personal insults, especially those using racist or sexist terms. 41 | - Unwelcome sexual attention. 42 | - Advocating for, or encouraging, any of the above behavior. 43 | - Repeated harassment of others. In general, if someone asks you to stop, then stop. 44 | 45 | ## When we disagree, try to understand why 46 | 47 | Disagreements, both social and technical, happen all the time and JS Foundation projects are no exception. It is important 48 | that we resolve disagreements and differing views constructively. Remember that we’re different. The strength of the JS 49 | Foundation comes from its varied community, people from a wide range of backgrounds. Different people have different 50 | perspectives on issues. Being unable to understand why someone holds a viewpoint doesn’t mean that they’re wrong. Don’t 51 | forget that it is human to err and blaming each other doesn’t get us anywhere. Instead, focus on helping to resolve issues 52 | and learning from mistakes. 53 | 54 | Original text courtesy of the Speak Up! project and Django Project. 55 | -------------------------------------------------------------------------------- /.github/labeler.yml: -------------------------------------------------------------------------------- 1 | package-cli: 2 | - 'packages/cli/**/*' 3 | package-diff: 4 | - 'packages/diff/**/*' 5 | package-common: 6 | - 'packages/common/**/*' 7 | - 'packages/config/**/*' 8 | package-core: 9 | - 'packages/core/**/*' 10 | package-fs: 11 | - 'packages/fs/**/*' 12 | package-inspector: 13 | - 'packages/inspector/**/*' 14 | package-transformers: 15 | - 'packages/transformers/**/*' 16 | documentation: 17 | - 'packages/docs/**/*' 18 | - '**/*.md' 19 | - '**/*.mdx' 20 | chore: 21 | - '.github/**/*' 22 | - 'scripts/**/*' 23 | - '**/test/**/*' 24 | - '**/*.d.ts' 25 | - 'tsconfig*.json' 26 | - 'jsconfig.json' 27 | - '.*' 28 | - '*.config.json' 29 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: 'Deploy Site on Release' 2 | 3 | on: 4 | release: 5 | types: ['published'] 6 | 7 | jobs: 8 | build: 9 | runs-on: 'ubuntu-latest' 10 | 11 | steps: 12 | - name: 'Checkout' 13 | uses: 'actions/checkout@master' 14 | 15 | - name: 'Use Node.js' 16 | uses: 'actions/setup-node@v1' 17 | 18 | - name: 'Cache node modules' 19 | uses: 'actions/cache@v1' 20 | env: 21 | cache-name: 'cache-node-modules' 22 | with: 23 | path: '~/.npm' # npm cache files are stored in `~/.npm` on Linux/macOS 24 | key: "${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}" 25 | restore-keys: | 26 | ${{ runner.os }}-build-${{ env.cache-name }}- 27 | ${{ runner.os }}-build- 28 | ${{ runner.os }}- 29 | 30 | - name: 'Install Dependencies' 31 | run: 'npm ci' 32 | 33 | - name: 'Publish to https://ibm.github.io/report-toolkit' 34 | run: 'npm run publish:docs' 35 | -------------------------------------------------------------------------------- /.github/workflows/label.yml: -------------------------------------------------------------------------------- 1 | # This workflow will triage pull requests and apply a label based on the 2 | # paths that are modified in the pull request. 3 | # 4 | # To use this workflow, you will need to set up a .github/labeler.yml 5 | # file with configuration. For more information, see: 6 | # https://github.com/actions/labeler/blob/master/README.md 7 | 8 | name: 'Add Labels to PRs' 9 | on: ['pull_request'] 10 | 11 | jobs: 12 | label: 13 | runs-on: 'ubuntu-latest' 14 | 15 | steps: 16 | - uses: 'actions/labeler@v2' 17 | with: 18 | repo-token: '${{ secrets.GITHUB_TOKEN }}' 19 | -------------------------------------------------------------------------------- /.github/workflows/nodejs.yml: -------------------------------------------------------------------------------- 1 | name: 'Build' 2 | 3 | on: ['push', 'pull_request'] 4 | 5 | jobs: 6 | build: 7 | name: 'Test on node ${{ matrix.node_version }} and ${{ matrix.os }}' 8 | runs-on: 'ubuntu-latest' 9 | strategy: 10 | matrix: 11 | node_version: [10, 12, 13, 14, 15] 12 | os: ['ubuntu-latest'] 13 | steps: 14 | - name: 'Checkout' 15 | uses: 'actions/checkout@master' 16 | 17 | - name: 'Use Node.js ${{ matrix.node_version }}' 18 | uses: 'actions/setup-node@v1' 19 | with: 20 | node-version: '${{ matrix.node_version }}' 21 | 22 | - name: 'Cache node modules' 23 | uses: 'actions/cache@v1' 24 | env: 25 | cache-name: 'cache-node-modules' 26 | with: 27 | path: '~/.npm' # npm cache files are stored in `~/.npm` on Linux/macOS 28 | key: "${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}" 29 | restore-keys: | 30 | ${{ runner.os }}-build-${{ env.cache-name }}- 31 | ${{ runner.os }}-build- 32 | ${{ runner.os }}- 33 | 34 | - name: 'Install Dependencies' 35 | run: 'npm ci' 36 | 37 | - name: 'Run Tests' 38 | run: 'npm test' 39 | 40 | - name: 'Upload Coverage to Codecov' 41 | uses: 'codecov/codecov-action@v1' 42 | with: 43 | token: '${{secrets.CODECOV_TOKEN}}' 44 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | .wallaby.js 63 | 64 | # terminalizer stuff 65 | *.gif 66 | report-toolkit*.yml 67 | 68 | # generated reports 69 | report*.json 70 | 71 | *.disabled 72 | *_scan-results 73 | 74 | dist/ 75 | .rollup 76 | packages/**/*.d.ts* 77 | packages/docs/src/pages/api 78 | packages/docs/.cache 79 | packages/docs/public 80 | packages/docs/src/pages/quick-start/cli-output.txt 81 | packages/docs/src/pages/config/recommended.js.txt 82 | -------------------------------------------------------------------------------- /.markdownlint.yml: -------------------------------------------------------------------------------- 1 | ul-style: 2 | style: 'dash' 3 | ul-indent: 4 | indent: 2 5 | commands-show-output: false 6 | no-bare-urls: false 7 | line-length: false 8 | single-title: false 9 | header-increment: false 10 | -------------------------------------------------------------------------------- /.mocharc.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | color: true, 5 | 'experimental-report': true, 6 | 'forbid-only': Boolean(process.env.CI), 7 | 'no-warnings': true, 8 | timeout: 5000, 9 | slow: 2000, 10 | require: ['esm', require.resolve('./packages/common/test/setup.js')] 11 | }; 12 | -------------------------------------------------------------------------------- /.rtkrc.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @type {import('./packages/common/src/config').ExportedConfig} 3 | */ 4 | exports.config = [ 5 | 'rtk:recommended', 6 | { 7 | rules: { 8 | 'long-timeout': {timeout: 5000} 9 | } 10 | } 11 | ]; 12 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # Apache License, Version 2.0 (Apache-2.0) 2 | 3 | Copyright 2019 IBM, contributors 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 6 | this file except in compliance with the License. You may obtain a copy of the 7 | License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software distributed 12 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 13 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 14 | specific language governing permissions and limitations under the License. 15 | -------------------------------------------------------------------------------- /babel.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "targets": { 7 | "browsers": "> 3%", 8 | "node": "10.0.0" 9 | }, 10 | "modules": false 11 | } 12 | ] 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /globals.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace NodeJS { 2 | interface Global { 3 | expect: any; 4 | proxyquire: any; 5 | sinon: any; 6 | } 7 | } 8 | 9 | declare var expect: any; 10 | declare var proxyquire: any; 11 | declare var sinon: any; 12 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.base.json", 3 | "compilerOptions": { 4 | "jsx": "react", 5 | "checkJs": true, 6 | "noImplicitAny": true 7 | }, 8 | "exclude": [ 9 | "**/node_modules/**/*", 10 | "**/dist/**/*", 11 | "**/coverage", 12 | "**/.history/**/*" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "lerna": "2.11.0", 3 | "packages": [ 4 | "packages/*" 5 | ], 6 | "version": "0.6.1", 7 | "command": { 8 | "publish": { 9 | "allowBranch": "master", 10 | "conventionalCommits": true, 11 | "message": "chore(release): %s", 12 | "createRelease": "github" 13 | } 14 | }, 15 | "ignoreChanges": [ 16 | "**/test/**", 17 | "**/**.spec.js", 18 | "**/*.md", 19 | "**/*.mdx" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /lint-staged.config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | '*.js': ['eslint --fix'], 5 | '*.{yml,md,mdx,toml}': ['prettier --write'], 6 | 'packages/*/package.json': ['syncpack format'], 7 | './README.md': [ 8 | 'sync-monorepo-packages --no-package-json -p packages/report-toolkit --force README.md', 9 | 'git add packages/report-toolkit/README.md' 10 | ] 11 | }; 12 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | publish = "packages/docs/public" 3 | # 1. bust the node_modules cache 4 | # 2. run `npm ci` (which calls `lerna-bootstrap`) 5 | # 3. build gatsby for production (without `--prefix-paths`) 6 | command = """ 7 | rm -rf $NETLIFY_CACHE_DIR/node_modules && \ 8 | npm ci && \ 9 | npm run build:docs:netlify \ 10 | """ 11 | # this, I think, tells netlify's built-in `npm install` to do nothing 12 | environment = { NPM_FLAGS = "--dry-run" } 13 | -------------------------------------------------------------------------------- /packages/README.md: -------------------------------------------------------------------------------- 1 | # What's What 2 | 3 | > Hi, you've found the source code. 4 | 5 | `report-toolkit` is a monorepo, powered by [Lerna](https://lerna.js.org). 6 | 7 | The package located in [the project root](https://github.com/IBM/report-toolkit) is in fact _not_ published to npm, and is only used for development. 8 | 9 | _This_ directory (`packages/`) contains all of the "workspaces" which `report-toolkit` project is built from. 10 | 11 | ### Directory-to-npm-Package Map 12 | 13 | > _Current as of 2020-02-05_ 14 | 15 | - `cli/` ([@report-toolkit/cli](https://npm.im/@report-toolkit/cli)): CLI for `report-toolkit` 16 | - `common/` ([@report-toolkit/common](https://npm.im/@report-toolkit/common)): Common modules & utils 17 | - `config/` ([@report-toolkit/config](https://npm.im/@report-toolkit/config)): Low-level configuration handling 18 | - `core/` ([@report-toolkit/core](https://npm.im/@report-toolkit/core)): Main, high-level API 19 | - `diff/` ([@report-toolkit/diff](https://npm.im/@report-toolkit/diff)): Low-level "diff" API 20 | - `docs/` (_not published_): Gatsby site; sources for [https://ibm.github.io/report-toolkit](https://ibm.github.io/report-toolkit) 21 | - `fs/` ([@report-toolkit/fs](https://npm.im/@report-toolkit/fs)): Filesystem interactions 22 | - `inspector/` ([@report-toolkit/inspector](https://npm.im/@report-toolkit/inspector)): Low-level "inspector" API 23 | - `report-toolkit/` ([report-toolkit](https://npm.im/report-toolkit)): Metapackage; pulls in all other published packages 24 | - `transformers/` ([@report-toolkit/transformers](https://npm.im/@report-toolkit/transformers)): Low-level "transformer" API 25 | 26 | ## OK THX. WHERE ARE THE DOCS 27 | 28 | Depends. 29 | 30 | The API docs are automatically generated from sources, and can be viewed at [https://ibm.github.io/report-toolkit/api](https://ibm.github.io/report-toolkit/api). 31 | 32 | "Everything else" can be found, along with the API, at [https://ibm.github.io/report-toolkit](https://ibm.github.io/report-toolkit); use the sidebar or double-cheeseburger menu to navigate. 33 | 34 | The _sources_ for "everything else" can be found in [`docs/src/pages/`](https://github.com/IBM/report-toolkit/tree/master/packages/docs/src/pages); look for `.mdx` files (sorry about the `.mdx` files). 35 | -------------------------------------------------------------------------------- /packages/cli/.eslintignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | -------------------------------------------------------------------------------- /packages/cli/LICENSE.md: -------------------------------------------------------------------------------- 1 | # Apache License, Version 2.0 (Apache-2.0) 2 | 3 | Copyright 2019 IBM, contributors 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 6 | this file except in compliance with the License. You may obtain a copy of the 7 | License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software distributed 12 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 13 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 14 | specific language governing permissions and limitations under the License. 15 | -------------------------------------------------------------------------------- /packages/cli/README.md: -------------------------------------------------------------------------------- 1 | # report-toolkit 2 | 3 | See docs at [https://ibm.github.io/report-toolkit](https://ibm.github.io/report-toolkit) 4 | -------------------------------------------------------------------------------- /packages/cli/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@report-toolkit/cli", 3 | "description": "", 4 | "version": "0.6.1", 5 | "author": "Christopher Hiller (https://boneskull.com/)", 6 | "bin": { 7 | "report-toolkit": "dist/report-toolkit-cli.cjs.js" 8 | }, 9 | "dependencies": { 10 | "@report-toolkit/common": "^0.6.1", 11 | "@report-toolkit/core": "^0.6.1", 12 | "@report-toolkit/fs": "^0.6.1", 13 | "cli-table3": "^0.5.1", 14 | "log-symbols": "^3.0.0", 15 | "strip-ansi": "^6.0.0", 16 | "term-size": "^2.2.1", 17 | "wrap-ansi": "^6.2.0", 18 | "yargs": "^15.4.1" 19 | }, 20 | "engines": { 21 | "node": ">=10" 22 | }, 23 | "files": [ 24 | "dist", 25 | "src" 26 | ], 27 | "keywords": [ 28 | "convert", 29 | "debug", 30 | "diagnose", 31 | "diagnostic", 32 | "diff", 33 | "inspect", 34 | "json", 35 | "node-report", 36 | "redact", 37 | "report", 38 | "sanitize", 39 | "secrets", 40 | "tool", 41 | "toolkit", 42 | "transform" 43 | ], 44 | "license": "Apache-2.0", 45 | "main": "dist/report-toolkit-cli.cjs.js", 46 | "module": "src/index.js", 47 | "publishConfig": { 48 | "access": "public" 49 | }, 50 | "repository": "ibm/report-toolkit.git" 51 | } 52 | -------------------------------------------------------------------------------- /packages/cli/src/commands/diff.js: -------------------------------------------------------------------------------- 1 | import {_} from '@report-toolkit/common'; 2 | import {observable as observableAPI} from '@report-toolkit/core'; 3 | 4 | import {terminalColumns, toOutput} from '../console-utils.js'; 5 | import { 6 | fromFilepathsToReports, 7 | getTransformerOptions, 8 | GROUPS, 9 | mergeCommandConfig, 10 | OPTIONS 11 | } from './common.js'; 12 | 13 | const {diff, transform, fromTransformerChain} = observableAPI; 14 | 15 | const OP_COLORS = _.toFrozenMap({ 16 | add: 'green', 17 | remove: 'red', 18 | replace: 'yellow' 19 | }); 20 | 21 | const OP_CODE = _.toFrozenMap({ 22 | add: 'A', 23 | remove: 'D', 24 | replace: 'M' 25 | }); 26 | 27 | /** 28 | * Best-effort reformatting RFC6902-style paths to something more familiar. 29 | * This will break if the key contains a `/`, which is "unlikely" (possible in the environment flag names) 30 | * @param {string} path - RFC6902-style path, e.g., `/header/foo/3/bar` 31 | * @returns Lodash-style keypath; e.g., `header.foo[3].bar` 32 | */ 33 | const formatKeypath = path => 34 | path 35 | .replace('/', '') 36 | .replace(/\/(\d+?)(\/)?/g, '[$1]$2') 37 | .replace(/\//g, '.'); 38 | 39 | export const command = 'diff '; 40 | 41 | export const desc = 'Diff two reports'; 42 | 43 | // @ts-ignore 44 | export const builder = yargs => 45 | yargs.options({ 46 | includeProp: { 47 | description: 'Include only properties (filter)', 48 | group: GROUPS.FILTER, 49 | nargs: 1, 50 | type: 'array', 51 | alias: 'i', 52 | coerce: _.castArray 53 | }, 54 | excludeProp: { 55 | description: 'Exclude properties (reject)', 56 | group: GROUPS.FILTER, 57 | nargs: 1, 58 | type: 'array', 59 | alias: 'x', 60 | coerce: _.castArray 61 | }, 62 | all: { 63 | description: 'Include everything in diff', 64 | group: GROUPS.FILTER, 65 | type: 'boolean', 66 | conflicts: ['i', 'x'] 67 | }, 68 | ...OPTIONS.OUTPUT, 69 | ...getTransformerOptions({sourceType: 'object'}) 70 | }); 71 | 72 | // @ts-ignore 73 | export const handler = argv => { 74 | const { 75 | file1, 76 | file2, 77 | includeProp: includeProperties, 78 | excludeProp: excludeProperties, 79 | all: includeAll 80 | } = argv; 81 | 82 | const config = mergeCommandConfig('diff', argv, { 83 | includeAll, 84 | includeProperties, 85 | excludeProperties, 86 | showSecretsUnsafe: false, 87 | sort: false, 88 | transformers: { 89 | table: { 90 | outputHeader: `Diff: ${file1} <=> ${file2}`, 91 | maxWidth: terminalColumns, 92 | colWidths: [5], 93 | fields: [ 94 | { 95 | color: ({op}) => OP_COLORS.get(op), 96 | label: 'Op', 97 | value: ({op}) => OP_CODE.get(op) 98 | }, 99 | { 100 | color: ({op}) => OP_COLORS.get(op), 101 | label: 'Field', 102 | value: ({field}) => formatKeypath(field) 103 | }, 104 | { 105 | label: file1, 106 | value: 'value' 107 | }, 108 | { 109 | label: file2, 110 | value: 'oldValue' 111 | } 112 | ] 113 | } 114 | } 115 | }); 116 | 117 | const source = diff( 118 | fromFilepathsToReports(file1), 119 | fromFilepathsToReports(file2), 120 | config 121 | ); 122 | 123 | fromTransformerChain(argv.transform, config) 124 | .pipe( 125 | transform(source, { 126 | beginWith: 'object', 127 | defaultTransformerConfig: config.transformers.table 128 | }), 129 | toOutput(argv.output, {color: argv.color}) 130 | ) 131 | .subscribe(); 132 | }; 133 | -------------------------------------------------------------------------------- /packages/cli/src/commands/index.js: -------------------------------------------------------------------------------- 1 | import * as diff from './diff.js'; 2 | import * as inspect from './inspect.js'; 3 | import * as listRules from './list-rules.js'; 4 | import * as redact from './redact.js'; 5 | import * as transform from './transform.js'; 6 | 7 | export {diff, inspect, listRules, redact, transform}; 8 | -------------------------------------------------------------------------------- /packages/cli/src/commands/inspect.js: -------------------------------------------------------------------------------- 1 | import {_, constants, observable} from '@report-toolkit/common'; 2 | import {observable as core} from '@report-toolkit/core'; 3 | 4 | import {terminalColumns, toOutput} from '../console-utils.js'; 5 | import { 6 | fromFilepathsToReports, 7 | GROUPS, 8 | mergeCommandConfig, 9 | OPTIONS, 10 | getTransformerOptions 11 | } from './common.js'; 12 | 13 | const {ERROR, WARNING, INFO, DEFAULT_SEVERITY} = constants; 14 | const {inspect, transform, fromTransformerChain} = core; 15 | const {filter, take} = observable; 16 | 17 | const DEFAULT_INSPECT_CONFIG = { 18 | transformers: { 19 | table: { 20 | colWidths: [12, 20, 15], 21 | fields: [ 22 | { 23 | color: ({severity}) => SEVERITY_COLOR_MAP.get(severity), 24 | label: 'Severity', 25 | value: ({severity}) => _.toUpper(severity) 26 | }, 27 | { 28 | label: 'File', 29 | value: 'filepath' 30 | }, 31 | { 32 | label: 'Rule', 33 | value: 'id' 34 | }, 35 | { 36 | label: 'Message', 37 | value: 'message' 38 | } 39 | ], 40 | maxWidth: terminalColumns, 41 | outputHeader: 'Diagnostic Report Inspection' 42 | } 43 | } 44 | }; 45 | 46 | const SEVERITY_COLOR_MAP = _.toFrozenMap({ 47 | error: 'red', 48 | warning: 'yellow', 49 | info: 'blue' 50 | }); 51 | 52 | export const command = 'inspect '; 53 | 54 | export const desc = 'Inspect Diagnostic Report file(s) for problems'; 55 | 56 | // @ts-ignore 57 | export const builder = yargs => 58 | yargs 59 | .positional('file', { 60 | coerce: _.castArray, 61 | type: 'array' 62 | }) 63 | .options({ 64 | severity: { 65 | choices: [ERROR, WARNING, INFO], 66 | default: DEFAULT_SEVERITY, 67 | description: 'Minimum threshold for message severity', 68 | group: GROUPS.FILTER 69 | }, 70 | ...OPTIONS.OUTPUT, 71 | ...getTransformerOptions({sourceType: 'object'}) 72 | }); 73 | 74 | // @ts-ignore 75 | export const handler = argv => { 76 | const config = mergeCommandConfig('inspect', argv, DEFAULT_INSPECT_CONFIG); 77 | const {file, severity, output, transform: transformer, color} = config; 78 | 79 | const source = inspect(fromFilepathsToReports(file, config), { 80 | ruleConfig: config.rules, 81 | severity 82 | }); 83 | 84 | // if any of the messages have a severity of `error`, then 85 | // exit with code 1. 86 | source 87 | .pipe( 88 | filter(({severity}) => severity === ERROR), 89 | take(1) 90 | ) 91 | .subscribe(() => { 92 | process.exitCode = 1; 93 | }); 94 | 95 | fromTransformerChain(transformer, config) 96 | .pipe( 97 | transform(source, { 98 | beginWith: 'object', 99 | defaultTransformerConfig: config.transformers.table 100 | }), 101 | toOutput(output, {color}) 102 | ) 103 | .subscribe(); 104 | }; 105 | -------------------------------------------------------------------------------- /packages/cli/src/commands/list-rules.js: -------------------------------------------------------------------------------- 1 | import {_, observable} from '@report-toolkit/common'; 2 | import {observable as observableAPI} from '@report-toolkit/core'; 3 | 4 | import {toOutput} from '../console-utils.js'; 5 | import {getTransformerOptions, mergeCommandConfig, OPTIONS} from './common.js'; 6 | 7 | const {map, share} = observable; 8 | const { 9 | fromRegisteredRuleDefinitions, 10 | transform, 11 | fromTransformerChain 12 | } = observableAPI; 13 | 14 | const DEFAULT_LIST_RULES_CONFIG = { 15 | fields: [ 16 | { 17 | label: 'Rule', 18 | value: 'id' 19 | }, 20 | { 21 | label: 'Description', 22 | value: _.getOr('(no description)', 'description') 23 | } 24 | ], 25 | transformers: { 26 | table: { 27 | outputHeader: 'Available Rules', 28 | colWidths: [20, 60], 29 | truncate: false 30 | } 31 | } 32 | }; 33 | 34 | export const command = 'list-rules'; 35 | 36 | export const desc = 'Lists built-in rules'; 37 | 38 | // @ts-ignore 39 | export const builder = yargs => 40 | yargs.options({ 41 | ..._.omit(['show-secrets-unsafe'], OPTIONS.OUTPUT), 42 | ...getTransformerOptions({sourceType: 'object'}) 43 | }); 44 | 45 | // @ts-ignore 46 | export const handler = argv => { 47 | const source = fromRegisteredRuleDefinitions().pipe( 48 | map(({id, meta}) => ({ 49 | id, 50 | description: _.getOr('(no description)', 'docs.description', meta) 51 | })), 52 | share() 53 | ); 54 | 55 | const config = mergeCommandConfig( 56 | 'list-rules', 57 | argv, 58 | DEFAULT_LIST_RULES_CONFIG 59 | ); 60 | fromTransformerChain(argv.transform, config) 61 | .pipe( 62 | transform(source, { 63 | beginWith: 'object', 64 | defaultTransformerConfig: config.transformers.table 65 | }), 66 | toOutput(argv.output, {color: argv.color}) 67 | ) 68 | .subscribe(); 69 | }; 70 | 71 | /** 72 | * @template T 73 | * @typedef {import('..').CLIArguments} CLIArguments 74 | */ 75 | -------------------------------------------------------------------------------- /packages/cli/src/commands/redact.js: -------------------------------------------------------------------------------- 1 | import {_, createDebugger, observable} from '@report-toolkit/common'; 2 | import {observable as api} from '@report-toolkit/core'; 3 | 4 | import {toOutput} from '../console-utils.js'; 5 | import { 6 | fromFilepathsToReports, 7 | GROUPS, 8 | mergeCommandConfig, 9 | OPTIONS 10 | } from './common.js'; 11 | const {transform, fromTransformerChain} = api; 12 | const {of, iif, concatMap} = observable; 13 | const debug = createDebugger('cli', 'commands', 'redact'); 14 | const DEFAULT_TRANSFORMER = 'json'; 15 | 16 | export const command = 'redact '; 17 | 18 | export const desc = 'Redact secrets from report file(s) and output JSON'; 19 | 20 | // @ts-ignore 21 | export const builder = yargs => 22 | yargs 23 | .positional('file', { 24 | coerce: _.castArray 25 | }) 26 | .options({ 27 | replace: { 28 | description: 'Replace file(s) in-place', 29 | type: 'boolean', 30 | group: GROUPS.OUTPUT 31 | }, 32 | ..._.omit(['output', 'show-secrets-unsafe'], OPTIONS.OUTPUT), 33 | ..._.defaultsDeep(OPTIONS.JSON_TRANSFORM, {pretty: {default: true}}) 34 | }); 35 | 36 | // @ts-ignore 37 | export const handler = argv => { 38 | const config = mergeCommandConfig('transform', argv); 39 | debug('complete command config: %O', config); 40 | // XXX: this is a really wonky way to do it; see `files` usage below 41 | const files = [...argv.file]; 42 | /** 43 | * @type {import('rxjs').Observable} 44 | */ 45 | const source = fromFilepathsToReports(argv.file, {showSecretsUnsafe: false}); 46 | fromTransformerChain(argv.transform, config) 47 | .pipe( 48 | transform(source, {defaultTransformer: DEFAULT_TRANSFORMER}), 49 | concatMap(result => 50 | iif( 51 | () => !argv.replace, 52 | of(result).pipe(toOutput(argv.output, {color: argv.color})), 53 | of(files.shift()).pipe( 54 | concatMap(file => of(result).pipe(toOutput(file, {color: false}))) 55 | ) 56 | ) 57 | ) 58 | ) 59 | .subscribe(); 60 | }; 61 | -------------------------------------------------------------------------------- /packages/cli/src/commands/transform.js: -------------------------------------------------------------------------------- 1 | import {_, createDebugger} from '@report-toolkit/common'; 2 | import {observable} from '@report-toolkit/core'; 3 | 4 | import {toOutput} from '../console-utils.js'; 5 | import { 6 | fromFilepathsToReports, 7 | mergeCommandConfig, 8 | OPTIONS, 9 | getTransformerOptions 10 | } from './common.js'; 11 | 12 | const {transform, fromTransformerChain} = observable; 13 | 14 | const DEFAULT_TRANSFORMER = 'json'; 15 | 16 | // in the case that `table` is chosen, use this output header. 17 | const DEFAULT_TRANSFORM_CONFIG = { 18 | transform: { 19 | table: { 20 | outputHeader: 'Transformation Result' 21 | } 22 | } 23 | }; 24 | 25 | const debug = createDebugger('cli', 'commands', 'transform'); 26 | 27 | export const command = 'transform '; 28 | 29 | export const desc = 'Transform a report'; 30 | 31 | // @ts-ignore 32 | export const builder = yargs => 33 | yargs 34 | .positional('file', { 35 | coerce: _.castArray, 36 | type: 'string', 37 | nargs: 1 38 | }) 39 | .options({ 40 | ...OPTIONS.OUTPUT, 41 | ...getTransformerOptions({ 42 | sourceType: 'report', 43 | defaultTransformer: DEFAULT_TRANSFORMER 44 | }) 45 | }); 46 | 47 | // @ts-ignore 48 | export const handler = argv => { 49 | /** 50 | * @type {Observable} 51 | */ 52 | const source = fromFilepathsToReports( 53 | argv.file, 54 | _.getOr( 55 | _.get('config.transform.showSecretsUnsafe', argv), 56 | 'showSecretsUnsafe', 57 | argv 58 | ) 59 | ); 60 | 61 | const config = mergeCommandConfig( 62 | 'transform', 63 | argv, 64 | DEFAULT_TRANSFORM_CONFIG 65 | ); 66 | debug('complete command config: %O', config); 67 | fromTransformerChain(argv.transform, config) 68 | .pipe( 69 | transform(source, {defaultTransformer: DEFAULT_TRANSFORMER}), 70 | toOutput(argv.output, {color: argv.color}) 71 | ) 72 | .subscribe(); 73 | }; 74 | 75 | /** 76 | * @template T,U 77 | * @typedef {import('@report-toolkit/transformers').Transformer} Transformer 78 | */ 79 | /** 80 | * @template T 81 | * @typedef {import('rxjs').Observable} Observable 82 | */ 83 | /** 84 | * @typedef {import('@report-toolkit/common').Report} Report 85 | */ 86 | -------------------------------------------------------------------------------- /packages/cli/src/console-utils.js: -------------------------------------------------------------------------------- 1 | import {colors, constants, observable} from '@report-toolkit/common'; 2 | import {writeFile as writeFileFs} from 'fs'; 3 | import {error, success} from 'log-symbols'; 4 | import stripAnsi from 'strip-ansi'; 5 | import termsize from 'term-size'; 6 | 7 | const {bindNodeCallback, iif, map, mergeMap, of, pipeIf, tap} = observable; 8 | const {DEFAULT_TERMINAL_WIDTH} = constants; 9 | const writeFile = bindNodeCallback(writeFileFs); 10 | /** 11 | * @param {string | number} text 12 | */ 13 | export const ok = text => 14 | colors.green(success) + ' ' + colors.green().bold(text); 15 | 16 | /** 17 | * @param {string | number} text 18 | */ 19 | export const fail = text => colors.red(error) + ' ' + colors.red().bold(text); 20 | 21 | /** 22 | * Writes CLI output to file or STDOUT 23 | * @todo might want to be moved to commands/common.js 24 | * @todo probably emits stuff it shouldn't 25 | * @param {string} [filepath] - If present, will write to file 26 | * @param {Object} [opts] 27 | * @param {boolean} [opts.color=true] 28 | * @returns {import('rxjs').OperatorFunction} 29 | */ 30 | export const toOutput = (filepath, {color = true} = {}) => observable => 31 | observable.pipe( 32 | map(String), 33 | pipeIf(color === false, map(stripAnsi)), 34 | mergeMap(output => 35 | iif( 36 | () => Boolean(filepath), 37 | writeFile(filepath, output), 38 | of(output).pipe( 39 | tap(res => { 40 | console.log(res); 41 | }) 42 | ) 43 | ) 44 | ) 45 | ); 46 | 47 | export {colors}; 48 | 49 | export const terminalColumns = termsize().columns || DEFAULT_TERMINAL_WIDTH; 50 | -------------------------------------------------------------------------------- /packages/cli/src/index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import { 4 | _, 5 | constants as commonConstants, 6 | createDebugger, 7 | enableDebugger 8 | } from '@report-toolkit/common'; 9 | import {loadConfig} from '@report-toolkit/core'; 10 | import { 11 | constants as fsConstants, 12 | fromFilesystemToConfig 13 | } from '@report-toolkit/fs'; 14 | import yargs from 'yargs/yargs.js'; 15 | 16 | import * as commands from './commands/index.js'; 17 | 18 | const {DEFAULT_TRANSFORMER, NAMESPACE, SHORT_NAMESPACE} = commonConstants; 19 | 20 | const debug = createDebugger('cli', 'main'); 21 | 22 | /** 23 | * @todo support color JSON output if TTY 24 | */ 25 | const main = () => { 26 | _.values(commands) 27 | .reduce( 28 | (parser, command) => parser.command(command), 29 | yargs() 30 | .scriptName(SHORT_NAMESPACE) 31 | .demandCommand( 32 | 1, 33 | 1, 34 | 'A command is required! See list above.', 35 | 'Use only one command, please!' 36 | ) 37 | .options({ 38 | color: { 39 | default: true, 40 | desc: 'Use color output if possible', 41 | type: 'boolean' 42 | }, 43 | debug: { 44 | alias: ['verbose'], 45 | desc: 'Enable debug output', 46 | global: true, 47 | type: 'boolean' 48 | }, 49 | rc: { 50 | desc: `Custom file or directory path to ${fsConstants.RC_FILENAME}`, 51 | normalize: true, 52 | requiresArg: true, 53 | type: 'string' 54 | } 55 | }) 56 | .wrap( 57 | process.stdout.columns ? Math.min(process.stdout.columns, 100) : 80 58 | ) 59 | .env(NAMESPACE) 60 | .help() 61 | .version() 62 | .middleware(async argv => { 63 | // "verbose" enables debug statements 64 | if (argv.verbose) { 65 | enableDebugger(); 66 | } 67 | 68 | debug('parsed CLI arguments: %O', argv); 69 | // any format other than the default "table" will not be in color 70 | argv.color = _.isUndefined(argv.color) 71 | ? argv.format !== DEFAULT_TRANSFORMER 72 | : argv.color; 73 | 74 | argv.config = await loadConfig( 75 | fromFilesystemToConfig({ 76 | searchPath: argv.rc 77 | }) 78 | ); 79 | 80 | return argv; 81 | }) 82 | ) 83 | .check(argv => { 84 | if (argv.output && _.castArray(argv.file).length > 1) { 85 | throw new Error('--output cannot be combined with multiple files'); 86 | } 87 | return true; 88 | }) 89 | .parse(process.argv.slice(2)); 90 | }; 91 | 92 | if (require.main === module) { 93 | main(); 94 | } 95 | 96 | export {main}; 97 | 98 | /** 99 | * @template T 100 | * @typedef {import('yargs').Arguments} CLIBaseArguments 101 | */ 102 | /** 103 | * @typedef {{debug?: boolean, rc?: string, config: object}} CLIGlobalArguments 104 | */ 105 | /** 106 | * @template T 107 | * @typedef {CLIBaseArguments} CLIArguments 108 | */ 109 | -------------------------------------------------------------------------------- /packages/cli/test/e2e/cli-helper.js: -------------------------------------------------------------------------------- 1 | import {createDebugger, _} from '@report-toolkit/common'; 2 | import csv from 'csvtojson'; 3 | import execa from 'execa'; 4 | 5 | const BIN_PATH = require.resolve('../..'); 6 | 7 | const debug = createDebugger('cli', 'test', 'e2e', 'cli-helper'); 8 | 9 | /** 10 | * Run executable with command, flags, etc. 11 | * Use when we're not sure if the executable will end in failure 12 | * @param {...string} flags - Flags 13 | * @returns {Promise} Result 14 | */ 15 | export const run = async (...flags) => runWithOptions(flags); 16 | 17 | /** 18 | * Run executable with command, flags, etc., but use `json` as final executable, 19 | * and parse the result into a JS object. The command itself will NOT; any 20 | * nonzero exit will be caught and resolved. If JSON parsing fails, only then will we get a rejection. 21 | * @param {string[]|string} flags - Any flags to pass to the executable 22 | * @param {execa.Options} opts - Options for execa 23 | * @returns {Promise} Result of `JSON.parse()` 24 | */ 25 | export const runAsJSON = async (flags, opts = {}) => { 26 | flags = [..._.castArray(flags), '-t', 'json']; 27 | let result; 28 | try { 29 | result = await runWithOptions(flags, opts); 30 | } catch (res) { 31 | result = res; 32 | } 33 | debug(`converting result of ${result.command} from JSON`); 34 | return JSON.parse(result.stdout); 35 | }; 36 | 37 | /** 38 | * Run executable with command, flags, etc., but use `csv` as final executable, 39 | * and parse the result into a JS object. Should be used with a command that we 40 | * expect NOT to exit with a nonzero code. 41 | * @param {...string} flags - Flags 42 | * @returns {Promise} Result of `JSON.parse()` 43 | */ 44 | export const runAsCSV = async (...flags) => { 45 | const result = await run(...flags, '-t', 'csv'); 46 | debug(`converting result of ${result.command} from CSV`); 47 | return csv().fromString(result.stdout); 48 | }; 49 | 50 | /** 51 | * Run executable, specifying additional options to execa 52 | * @param {string[]} flags - Any flags to pass to the executable 53 | * @param {execa.Options} opts - Options for execa 54 | * @returns {Promise} Result 55 | */ 56 | export const runWithOptions = (flags, opts = {}) => 57 | execa(process.execPath, [BIN_PATH, ...flags, '--verbose'], opts); 58 | -------------------------------------------------------------------------------- /packages/cli/test/e2e/common.spec.js: -------------------------------------------------------------------------------- 1 | import {run} from './cli-helper.js'; 2 | 3 | describe('@report-toolkit/cli', function () { 4 | describe('when run without parameters', function () { 5 | it('should exit with code 1', function () { 6 | return expect(run(), 'to be rejected with error satisfying', { 7 | exitCode: 1 8 | }); 9 | }); 10 | 11 | it('should complain about non-option arguments', function () { 12 | return expect(run(), 'to be rejected with error satisfying', { 13 | stderr: /A command is required/ 14 | }); 15 | }); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /packages/cli/test/e2e/diff.spec.js: -------------------------------------------------------------------------------- 1 | import {runWithOptions} from './cli-helper.js'; 2 | 3 | const REPORT_001_FILEPATH = require.resolve( 4 | '@report-toolkit/common/test/fixture/reports/report-001.json' 5 | ); 6 | const REPORT_002_FILEPATH = require.resolve( 7 | '@report-toolkit/common/test/fixture/reports/report-002-library-mismatch.json' 8 | ); 9 | 10 | describe('@report-toolkit/cli:command:diff', function () { 11 | describe('when run with a single report file', function () { 12 | it('should exit with code 1', function () { 13 | return expect( 14 | runWithOptions(['diff', REPORT_001_FILEPATH]), 15 | 'to be rejected with error satisfying', 16 | { 17 | exitCode: 1 18 | } 19 | ); 20 | }); 21 | }); 22 | 23 | describe('when run with two report files', function () { 24 | it('should exit with code 0', function () { 25 | return expect( 26 | runWithOptions(['diff', REPORT_001_FILEPATH, REPORT_002_FILEPATH]), 27 | 'to be fulfilled with value satisfying', 28 | { 29 | exitCode: 0 30 | } 31 | ); 32 | }); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /packages/cli/test/e2e/inspect.spec.js: -------------------------------------------------------------------------------- 1 | import {tmpdir} from 'os'; 2 | 3 | import {run, runAsJSON} from './cli-helper.js'; 4 | 5 | const REPORT_001_FILEPATH = require.resolve( 6 | '@report-toolkit/common/test/fixture/reports/report-002-library-mismatch.json' 7 | ); 8 | const REPORT_002_FILEPATH = require.resolve( 9 | '@report-toolkit/common/test/fixture/reports/report-002-library-mismatch.json' 10 | ); 11 | 12 | describe('@report-toolkit/cli:command:inspect', function () { 13 | describe('when run without parameters', function () { 14 | it('should exit with code 1', function () { 15 | return expect(run('inspect'), 'to be rejected with error satisfying', { 16 | exitCode: 1 17 | }); 18 | }); 19 | }); 20 | 21 | describe('when it cannot find a config file', function () { 22 | it('should enable all rules', function () { 23 | return expect( 24 | runAsJSON(['inspect', REPORT_001_FILEPATH], { 25 | cwd: tmpdir() 26 | }), 27 | 'when fulfilled', 28 | 'to have items satisfying', 29 | { 30 | message: expect.it('to be a', 'string'), 31 | severity: 'error', 32 | id: 'library-mismatch', 33 | filepath: REPORT_002_FILEPATH 34 | } 35 | ); 36 | }); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /packages/cli/test/e2e/list-rules.spec.js: -------------------------------------------------------------------------------- 1 | import {runAsCSV, runAsJSON} from './cli-helper.js'; 2 | 3 | describe('@report-toolkit/cli:command:list-rules', function () { 4 | it('should list available rules', function () { 5 | return expect( 6 | runAsJSON('list-rules'), 7 | 'to be fulfilled with value satisfying', 8 | expect.it('to be an', Array).and('to have items satisfying', { 9 | id: expect.it('to be a', 'string'), 10 | description: expect.it('to be a', 'string') 11 | }) 12 | ); 13 | }); 14 | 15 | describe('when used with transform', function () { 16 | describe('csv', function () { 17 | it('should list available rules', function () { 18 | return expect( 19 | runAsCSV('list-rules'), 20 | 'to be fulfilled with value satisfying', 21 | expect.it('to be an', Array).and('to have items satisfying', { 22 | Rule: expect.it('to be a', 'string'), 23 | Description: expect.it('to be a', 'string') 24 | }) 25 | ); 26 | }); 27 | }); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /packages/cli/test/e2e/transform.spec.js: -------------------------------------------------------------------------------- 1 | // @ts-ignore 2 | import {readFileSync} from 'fs'; 3 | 4 | import {run, runAsJSON} from './cli-helper.js'; 5 | 6 | const REPORT_005_FILEPATH = require.resolve( 7 | '@report-toolkit/common/test/fixture/reports/report-005-secrets.json' 8 | ); 9 | 10 | describe('@report-toolkit/cli:command:transform', function () { 11 | describe('when no file specified', function () { 12 | it('should fail', function () { 13 | return expect(run('transform'), 'to be rejected with error satisfying', { 14 | exitCode: 1 15 | }); 16 | }); 17 | }); 18 | 19 | describe('when no --transform specified', function () { 20 | it('should redact and output JSON', function () { 21 | // report-005 is the same as report-001, except it is not completely redacted. 22 | // when it's redacted, it's equal to report-001. 23 | return expect( 24 | run('transform', REPORT_005_FILEPATH, '--pretty'), 25 | 'to be fulfilled with value satisfying', 26 | { 27 | exitCode: 0, 28 | stdout: readFileSync( 29 | require.resolve( 30 | '@report-toolkit/common/test/fixture/reports/report-001.json' 31 | ), 32 | 'utf8' 33 | ).trim() // zap trailing space in this file 34 | } 35 | ); 36 | }); 37 | }); 38 | 39 | describe('when compatible --transforms specified', function () { 40 | it('should succeed', function () { 41 | return expect( 42 | // filters contrived, as -i header.release.name would work 43 | runAsJSON([ 44 | 'transform', 45 | REPORT_005_FILEPATH, 46 | '-t', 47 | 'filter', 48 | '-i', 49 | 'header.release', 50 | '-x', 51 | 'header.release.headersUrl', 52 | '-x', 53 | 'header.release.sourceUrl' 54 | ]), 55 | 'to be fulfilled with', 56 | { 57 | header: { 58 | release: {name: 'node'} 59 | } 60 | } 61 | ); 62 | }); 63 | }); 64 | }); 65 | -------------------------------------------------------------------------------- /packages/common/.eslintignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | -------------------------------------------------------------------------------- /packages/common/LICENSE.md: -------------------------------------------------------------------------------- 1 | # Apache License, Version 2.0 (Apache-2.0) 2 | 3 | Copyright 2019 IBM, contributors 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 6 | this file except in compliance with the License. You may obtain a copy of the 7 | License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software distributed 12 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 13 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 14 | specific language governing permissions and limitations under the License. 15 | -------------------------------------------------------------------------------- /packages/common/README.md: -------------------------------------------------------------------------------- 1 | # report-toolkit 2 | 3 | See docs at [https://ibm.github.io/report-toolkit](https://ibm.github.io/report-toolkit) 4 | -------------------------------------------------------------------------------- /packages/common/diagnostic-report.d.ts: -------------------------------------------------------------------------------- 1 | export interface ReportHeaderCpu { 2 | model: string; 3 | speed: number; 4 | user: number; 5 | nice: number; 6 | sys: number; 7 | idle: number; 8 | irq: number; 9 | } 10 | 11 | export interface ReportHeader { 12 | event: string; 13 | trigger: string; 14 | filename: string; 15 | dumpEventTime: string; 16 | dumpEventTimeStamp: string; 17 | processId: number; 18 | threadId: number | null; 19 | cwd: string; 20 | commandLine: string[]; 21 | nodejsVersion: string; 22 | wordSize: number; 23 | arch: string; 24 | platform: string; 25 | componentVersions: { 26 | [key: string]: string; 27 | }; 28 | release: { 29 | name: string; 30 | headersUrl: string; 31 | sourceUrl: string; 32 | }; 33 | osName: string; 34 | osRelease: string; 35 | osVersion: string; 36 | osMachine: string; 37 | cpus: ReportHeaderCpu[]; 38 | host: string; 39 | } 40 | 41 | export interface ReportJSStack { 42 | message: string; 43 | stack: string[]; 44 | } 45 | 46 | export interface NativeStackFrame { 47 | pc: string; 48 | symbol: string; 49 | } 50 | 51 | export interface ReportHeapSpace { 52 | memorySize: number; 53 | committedMemory: number; 54 | capacity: number; 55 | used: number; 56 | available: number; 57 | } 58 | 59 | export interface ReportJSHeap { 60 | totalMemory: number; 61 | totalCommittedMemory: number; 62 | usedMemory: number; 63 | availableMemory: number; 64 | memoryLimit: number; 65 | heapSpaces: { 66 | [key: string]: ReportHeapSpace; 67 | }; 68 | } 69 | 70 | export interface ReportResourceUsage { 71 | userCpuSeconds: number; 72 | kernelCpuSeconds: number; 73 | cpuConsumptionPercent: number; 74 | maxRss: number; 75 | pageFaults: { 76 | IORequired: number; 77 | IONotRequired: number; 78 | }; 79 | fsActivity: { 80 | reads: number; 81 | writes: number; 82 | }; 83 | } 84 | 85 | // TODO: Multiple variants, CBA for PoC 86 | type ReportUVItem = {}; 87 | 88 | export type ReportLimit = number | 'unlimited'; 89 | 90 | export interface ReportUserLimit { 91 | hard: ReportLimit; 92 | soft: ReportLimit; 93 | } 94 | 95 | export interface DiagnosticReport { 96 | header: ReportHeader; 97 | javascriptStack: ReportJSStack; 98 | nativeStack: NativeStackFrame[]; 99 | javascriptHeap: ReportJSHeap; 100 | resourceUsage: ReportResourceUsage; 101 | libuv: ReportUVItem[]; 102 | environmentVariables: { 103 | [key: string]: string; 104 | }; 105 | // not present on reports generated on win32 systems 106 | userLimits?: { 107 | [key: string]: ReportUserLimit; 108 | }; 109 | sharedObjects: string[]; 110 | workers: DiagnosticReport[]; 111 | } 112 | -------------------------------------------------------------------------------- /packages/common/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@report-toolkit/common", 3 | "version": "0.6.1", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "debug": { 8 | "version": "4.3.1", 9 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", 10 | "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", 11 | "requires": { 12 | "ms": "2.1.2" 13 | } 14 | }, 15 | "kleur": { 16 | "version": "3.0.3", 17 | "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", 18 | "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==" 19 | }, 20 | "lodash": { 21 | "version": "4.17.20", 22 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", 23 | "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" 24 | }, 25 | "ms": { 26 | "version": "2.1.2", 27 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 28 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 29 | }, 30 | "p-is-promise": { 31 | "version": "3.0.0", 32 | "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-3.0.0.tgz", 33 | "integrity": "sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==" 34 | }, 35 | "rxjs": { 36 | "version": "6.6.3", 37 | "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz", 38 | "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==", 39 | "requires": { 40 | "tslib": "^1.9.0" 41 | } 42 | }, 43 | "traverse": { 44 | "version": "0.6.6", 45 | "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz", 46 | "integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=" 47 | }, 48 | "tslib": { 49 | "version": "1.14.1", 50 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", 51 | "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /packages/common/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@report-toolkit/common", 3 | "description": "", 4 | "version": "0.6.1", 5 | "author": "Christopher Hiller (https://boneskull.com/)", 6 | "dependencies": { 7 | "debug": "^4.3.1", 8 | "kleur": "^3.0.3", 9 | "lodash": "^4.17.20", 10 | "p-is-promise": "^3.0.0", 11 | "rxjs": "^6.6.3", 12 | "traverse": "^0.6.6" 13 | }, 14 | "engines": { 15 | "node": ">=10" 16 | }, 17 | "files": [ 18 | "diagnostic-report-v2.schema.json", 19 | "diagnostic-report.d.ts", 20 | "dist", 21 | "src" 22 | ], 23 | "keywords": [ 24 | "convert", 25 | "debug", 26 | "diagnose", 27 | "diagnostic", 28 | "diff", 29 | "inspect", 30 | "json", 31 | "node-report", 32 | "redact", 33 | "report", 34 | "sanitize", 35 | "secrets", 36 | "tool", 37 | "toolkit", 38 | "transform" 39 | ], 40 | "license": "Apache-2.0", 41 | "main": "dist/report-toolkit-common.cjs.js", 42 | "module": "src/index.js", 43 | "publishConfig": { 44 | "access": "public" 45 | }, 46 | "repository": "ibm/report-toolkit.git" 47 | } 48 | -------------------------------------------------------------------------------- /packages/common/src/configs/recommended.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The "recommended" config, which can be referenced by its alias, `rtk:recommended`. 3 | * This is _also_ the _default_ config if no config file is used. 4 | * @type {import('../config').ConfigListItem[]} 5 | **/ 6 | exports.config = [ 7 | { 8 | rules: { 9 | 'cpu-usage': true, 10 | 'library-mismatch': true, 11 | 'long-timeout': true, 12 | 'memory-usage': true 13 | } 14 | } 15 | ]; 16 | 17 | /** 18 | * @type {import('../config').BuiltinConfigAliases} 19 | */ 20 | exports.alias = 'rtk:recommended'; 21 | -------------------------------------------------------------------------------- /packages/common/src/constants.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Known root properties of a Diagnostic Report. To be processed, an object must have *all* of these properties. The current list _in order_: 3 | * - `header` 4 | * - `javascriptStack` 5 | * - `nativeStack` 6 | * - `javascriptHeap` 7 | * - `resourceUsage` 8 | * - `libuv` 9 | * - `workers` (v2) 10 | * - `environmentVariables` 11 | * - `userLimits` 12 | * - `sharedObjects` 13 | */ 14 | export const REPORT_KNOWN_ROOT_PROPERTIES = Object.freeze([ 15 | 'header', 16 | 'javascriptStack', 17 | 'nativeStack', 18 | 'javascriptHeap', 19 | 'resourceUsage', 20 | 'libuv', 21 | 'workers', 22 | 'environmentVariables', 23 | 'userLimits', 24 | 'sharedObjects' 25 | ]); 26 | 27 | /** 28 | * "Error" severity. The highest severity, and the default. 29 | */ 30 | export const ERROR = 'error'; 31 | 32 | /** 33 | * "Warning" severity. 34 | */ 35 | export const WARNING = 'warning'; 36 | 37 | /** 38 | * "Info" severity. The lowest severity. 39 | */ 40 | export const INFO = 'info'; 41 | 42 | /** 43 | * Project namespace 44 | */ 45 | export const NAMESPACE = 'report-toolkit'; 46 | 47 | /** 48 | * Short project namespace 49 | */ 50 | export const SHORT_NAMESPACE = 'rtk'; 51 | 52 | /** 53 | * Text to use in display if no filepath found 54 | */ 55 | export const NO_FILEPATH = '(no filepath)'; 56 | 57 | /** 58 | * @hidden 59 | */ 60 | export const MULTIPLE_FILEPATHS = '(multiple files)'; 61 | 62 | /** 63 | * @hidden 64 | */ 65 | export const DEFAULT_TRANSFORMER = 'table'; 66 | 67 | /** 68 | * The string token used to replace secrets when redacting from a report. 69 | */ 70 | export const REDACTED_TOKEN = '[REDACTED]'; 71 | 72 | /** 73 | * @hidden 74 | */ 75 | export const DEFAULT_TERMINAL_WIDTH = 80; 76 | 77 | /** 78 | * Potential severities of Messages reported by the inspector. 79 | * @enum {number} 80 | */ 81 | export const SEVERITIES = Object.freeze({ 82 | [ERROR]: 30, 83 | [INFO]: 10, 84 | [WARNING]: 20 85 | }); 86 | 87 | /** 88 | * Typically useless keypaths to explicitly omit from diffs. Anything here should be more specific than what's in {@link DEFAULT_DIFF_INCLUDE}. 89 | */ 90 | export const DEFAULT_DIFF_EXCLUDE = Object.freeze([ 91 | 'header.filename', // typically redundant 92 | 'header.dumpEventTime', // always different 93 | 'header.dumpEventTimeStamp', // ditto 94 | 'header.cpus' // can vary wildly 95 | ]); 96 | 97 | /** 98 | * Things we explicitly want to show in the diffs. Use {@link DEFAULT_DIFF_EXCLUDE} to exclude any child properties of these. 99 | */ 100 | export const DEFAULT_DIFF_INCLUDE = Object.freeze([ 101 | 'header', 102 | 'environmentVariables', 103 | 'userLimits', 104 | 'sharedObjects', 105 | 'libuv' 106 | ]); 107 | 108 | /** 109 | * Default severity across system 110 | */ 111 | export const DEFAULT_SEVERITY = WARNING; 112 | -------------------------------------------------------------------------------- /packages/common/src/debug.js: -------------------------------------------------------------------------------- 1 | import debug from 'debug'; 2 | 3 | import {SHORT_NAMESPACE} from './constants.js'; 4 | import {tap} from './observable.js'; 5 | import {_} from './util.js'; 6 | 7 | const NAMESPACE_SEPARATOR = ':'; 8 | const APP_NAMESPACE = `${SHORT_NAMESPACE}*`; 9 | 10 | const joinDebugNamespace = _.join(NAMESPACE_SEPARATOR); 11 | 12 | /** 13 | * Returns a namespace for debug pkg 14 | * @param {string[]} args Strings to append to debug namespace 15 | */ 16 | const getDebugNamespace = (...args) => 17 | joinDebugNamespace([SHORT_NAMESPACE, ...args]); 18 | 19 | /** 20 | * Creates a `Debugger` instance with proper namespace 21 | * @see https://npm.im/debug 22 | * @param {string[]} args 23 | */ 24 | export const createDebugger = (...args) => 25 | _.pipe(getDebugNamespace, debug)(...args); 26 | 27 | /** 28 | * Enables entire debug namespace for this module. Calling this is just like 29 | * setting `DEBUG=RTK*` in the environment. 30 | */ 31 | export const enableDebugger = () => { 32 | debug.enable(APP_NAMESPACE); 33 | }; 34 | 35 | /** 36 | * Creates an RxJS debug "operator" using the supplied namespace(s). The 37 | * resulting operator is essentially like 38 | * [tap](https://rxjs.dev/api/operators/tap), except whatever is returned is 39 | * handed to a `Debugger` instance. The resulting operator accepts a single 40 | * function which receives a value from the source `Observable`. You can return 41 | * an array of values to make use `Debugger`'s sprintf-style formatting. 42 | * @param {string[]} args - Zero or more namespace tokens 43 | */ 44 | export const createDebugPipe = (...args) => { 45 | const debug = createDebugger(...args); 46 | 47 | return ( 48 | /** 49 | * @template T 50 | * @param {(arg: T) => any} fn 51 | * @returns {import('rxjs').OperatorFunction} 52 | */ 53 | fn => observable => 54 | observable.pipe( 55 | tap(value => { 56 | /** 57 | * @type {any[]} 58 | */ 59 | const msg = _.castArray(fn(value)); 60 | if (msg.length) { 61 | debug.apply(null, msg); 62 | } 63 | }) 64 | ) 65 | ); 66 | }; 67 | -------------------------------------------------------------------------------- /packages/common/src/error.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Represents a "known" Error 3 | */ 4 | export class RTkError extends Error { 5 | /** 6 | * Assigns custom props 7 | * @param {string} code - Error code 8 | * @param {string} message - Error message 9 | * @param {Partial} [opts] - Options 10 | */ 11 | constructor(message, code, opts = {}) { 12 | super(message); 13 | 14 | this.code = code; 15 | 16 | const {data, url} = opts; 17 | this.data = data; 18 | this.url = url; 19 | } 20 | 21 | /** 22 | * Create a RTkError 23 | * @param {string} [code] - Error code 24 | * @param {string} [message] - Error message 25 | * @param {Partial} opts - Options 26 | */ 27 | static create( 28 | code = RTKERR_UNKNOWN_ERROR, 29 | message = '(unknown error)', 30 | opts = {} 31 | ) { 32 | return new RTkError(message, code, opts); 33 | } 34 | } 35 | 36 | export const RTKERR_INVALID_CLI_OPTION = 'RTKERR_INVALID_CLI_OPTION'; 37 | export const RTKERR_INVALID_CONFIG = 'RTKERR_INVALID_CONFIG'; 38 | export const RTKERR_INVALID_PARAMETER = 'RTKERR_INVALID_PARAMETER'; 39 | export const RTKERR_INVALID_REPORT = 'RTKERR_INVALID_REPORT'; 40 | export const RTKERR_INVALID_RULE_CONFIG = 'RTKERR_INVALID_RULE_CONFIG'; 41 | export const RTKERR_INVALID_RULE_DEFINITION = 'RTKERR_INVALID_RULE_DEFINITION'; 42 | export const RTKERR_INVALID_SCHEMA = 'RTKERR_INVALID_SCHEMA'; 43 | export const RTKERR_INVALID_TRANSFORMER_HEAD = 44 | 'RTKERR_INVALID_TRANSFORMER_HEAD'; 45 | export const RTKERR_INVALID_TRANSFORMER_PIPE = 46 | 'RTKERR_INVALID_TRANSFORMER_PIPE'; 47 | export const RTKERR_INVALID_TRANSFORMER_TAIL = 48 | 'RTKERR_INVALID_TRANSFORMER_TAIL'; 49 | export const RTKERR_MISSING_CONFIG = 'RTKERR_MISSING_CONFIG'; 50 | export const RTKERR_RULE_NAME_COLLISION = 'RTKERR_RULE_NAME_COLLISION'; 51 | export const RTKERR_UNKNOWN_BUILTIN_CONFIG = 'RTKERR_UNKNOWN_BUILTIN_CONFIG'; 52 | export const RTKERR_UNKNOWN_ERROR = 'RTKERR_UNKNOWN_ERROR'; 53 | export const RTKERR_UNKNOWN_TRANSFORMER = 'RTKERR_UNKNOWN_TRANSFORMER'; 54 | 55 | export const createRTkError = RTkError.create; 56 | 57 | /** 58 | * @typedef {object} RTkErrorOptions 59 | * @property {any} data - Extra data 60 | * @property {string} url - URL for more information 61 | */ 62 | -------------------------------------------------------------------------------- /packages/common/src/index.js: -------------------------------------------------------------------------------- 1 | // babel doesn't like "export * as foo from 'bar'" w/o a plugin, so 2 | // not doing that now. 3 | 4 | import * as constants from './constants.js'; 5 | import * as error from './error.js'; 6 | import * as observable from './observable.js'; 7 | import * as symbols from './symbols.js'; 8 | import * as config from './config.js'; 9 | import {_} from './util.js'; 10 | export {createDebugger, enableDebugger, createDebugPipe} from './debug.js'; 11 | 12 | export {constants, error, observable, _, symbols, config}; 13 | export {redact} from './redact.js'; 14 | export {default as colors} from 'kleur'; 15 | export {Report, createReport, isReport, isReportLike} from './report.js'; 16 | -------------------------------------------------------------------------------- /packages/common/src/report.js: -------------------------------------------------------------------------------- 1 | import {NO_FILEPATH, REPORT_KNOWN_ROOT_PROPERTIES} from './constants.js'; 2 | import {createDebugger} from './debug.js'; 3 | import {createRTkError, RTKERR_INVALID_REPORT} from './error.js'; 4 | import {kReport, kReportFilepath} from './symbols.js'; 5 | import {_} from './util.js'; 6 | 7 | const debug = createDebugger('common', 'report'); 8 | 9 | /** 10 | * Represents a [Diagnostic Report](https://nodejs.org/api/process.html#process_process_report_getreport_err). 11 | */ 12 | class Report { 13 | /** 14 | * Creates shallow copies of root props in `report`; assigns internally-used `Symbol`s. 15 | * @param {import('../diagnostic-report').DiagnosticReport} report - Raw object 16 | * @param {string?} filepath - Original filepath of report, if available. Defaults to {@link NO_FILEPATH} 17 | */ 18 | constructor(report, filepath = NO_FILEPATH) { 19 | if (!Report.isReportLike(report)) { 20 | throw createRTkError(RTKERR_INVALID_REPORT, `Invalid report!`); 21 | } 22 | 23 | this.header = {...report.header}; 24 | this.javascriptStack = {...report.javascriptStack}; 25 | this.nativeStack = [...report.nativeStack]; 26 | this.javascriptHeap = {...report.javascriptHeap}; 27 | this.resourceUsage = {...report.resourceUsage}; 28 | this.libuv = [...report.libuv]; 29 | this.workers = [...(report.workers || [])]; 30 | this.environmentVariables = {...report.environmentVariables}; 31 | this.userLimits = {...report.userLimits}; 32 | this.sharedObjects = [...report.sharedObjects]; 33 | 34 | this[kReportFilepath] = filepath; 35 | this[kReport] = true; 36 | 37 | debug( 38 | `created Report generated on ${this.header.dumpEventTime} w/ filepath ${this[kReportFilepath]}` 39 | ); 40 | } 41 | 42 | /** 43 | * Original filepath of report, if available. Defaults to {@link NO_FILEPATH}. 44 | */ 45 | get filepath() { 46 | return /** @type {string} */ (this[kReportFilepath]); 47 | } 48 | 49 | /** 50 | * Creates a read-only {@link Report} from a {@link ReportLike} value. 51 | * Use this instead of `new Report()`! 52 | * @param {ReportLike} rawReport 53 | * @param {string} filepath 54 | */ 55 | static create(rawReport, filepath) { 56 | return Object.freeze(new Report(rawReport, filepath)); 57 | } 58 | 59 | /** 60 | * Returns `true` if the value is an object having a property `report-toolkit-report` `Symbol` with value `true`. 61 | * @param {any} value 62 | */ 63 | static isReport(value) { 64 | // @ts-ignore 65 | return _.isObject(value) && value[kReport] === true; 66 | } 67 | 68 | /** 69 | * Returns `true` if `value` has all expected root properties of a Diagnostic Report (as returned by [process.report.getReport()](https://nodejs.org/api/process.html#process_process_report_getreport_err)), or is a {@link Report}. 70 | * @param {any} value 71 | */ 72 | static isReportLike(value) { 73 | if (Report.isReport(value)) { 74 | return true; 75 | } 76 | if (_.isObject(value)) { 77 | // win32 doesn't report 'userLimits' 78 | let propsToCheck = 79 | _.get('header.platform', value) === 'win32' 80 | ? _.pull('userLimits', REPORT_KNOWN_ROOT_PROPERTIES) 81 | : REPORT_KNOWN_ROOT_PROPERTIES; 82 | if (_.getOr(0, 'header.reportVersion', value) < 2) { 83 | propsToCheck = _.pull('workers', propsToCheck); 84 | } 85 | return _.every(key => { 86 | const hasValue = _.has(key, value); 87 | if (!hasValue) { 88 | debug(`report is missing prop "${key}"`); 89 | } 90 | return hasValue; 91 | }, propsToCheck); 92 | } 93 | } 94 | } 95 | 96 | export const createReport = Report.create; 97 | export const isReport = Report.isReport; 98 | export const isReportLike = Report.isReportLike; 99 | 100 | export {Report}; 101 | 102 | /** 103 | * Either a {@link Report} or an object with all of the required props. See {@link Report.isReportLike} 104 | * @typedef {import('../diagnostic-report').DiagnosticReport|Report} ReportLike 105 | */ 106 | -------------------------------------------------------------------------------- /packages/common/src/symbols.js: -------------------------------------------------------------------------------- 1 | export const kFlattenedConfig = Symbol('report-toolkit-flattened-config'); 2 | export const kRedacted = Symbol('report-toolkit-redacted'); 3 | export const kReport = Symbol('report-toolkit-report'); 4 | export const kReportFilepath = Symbol('report-toolkit-report-filepath'); 5 | export const kRuleId = Symbol('report-toolkit-rule-id'); 6 | export const kRuleInspect = Symbol('report-toolkit-rule-inspect'); 7 | export const kRuleMeta = Symbol('report-toolkit-rule-meta'); 8 | -------------------------------------------------------------------------------- /packages/common/test/config.spec.js: -------------------------------------------------------------------------------- 1 | import { 2 | filterEnabledRules, 3 | parseConfig, 4 | normalizeFlattenedConfig 5 | } from '../src/config.js'; 6 | import {of} from '../src/observable.js'; 7 | import {kFlattenedConfig} from '../src/symbols.js'; 8 | import { 9 | RTKERR_UNKNOWN_BUILTIN_CONFIG, 10 | RTKERR_INVALID_CONFIG 11 | } from '../src/error.js'; 12 | 13 | describe('@report-toolkit/common:config', function () { 14 | describe('function', function () { 15 | describe('filterEnabledRules()', function () { 16 | it('should return an array of enabled rule IDs', function () { 17 | expect( 18 | // @ts-ignore -- partial type OK here 19 | filterEnabledRules({rules: {bar: false, foo: true}}), 20 | 'to equal', 21 | ['foo'] 22 | ); 23 | }); 24 | }); 25 | 26 | describe('parseConfig()', function () { 27 | describe('when the ExportedConfig has already been flattened', function () { 28 | it('should return the Config', function () { 29 | const config = normalizeFlattenedConfig({}); 30 | expect( 31 | of([config]).pipe(parseConfig()), 32 | 'to complete with value', 33 | config 34 | ); 35 | }); 36 | }); 37 | 38 | describe('when the Config has already been flattened', function () { 39 | it('should return the Config', function () { 40 | const config = normalizeFlattenedConfig({}); 41 | expect( 42 | of(config).pipe(parseConfig()), 43 | 'to complete with value', 44 | config 45 | ); 46 | }); 47 | }); 48 | 49 | describe('when the ExportedConfig references a valid builtin', function () { 50 | it('should return a flattened Config', function () { 51 | /** @type {import('../src/config').ExportedConfig} */ 52 | const config = ['rtk:recommended']; 53 | expect(of(config).pipe(parseConfig()), 'to complete with value', { 54 | commands: {}, 55 | rules: { 56 | 'cpu-usage': true, 57 | 'library-mismatch': true, 58 | 'long-timeout': true, 59 | 'memory-usage': true 60 | }, 61 | plugins: [], 62 | transformers: {}, 63 | [kFlattenedConfig]: true 64 | }); 65 | }); 66 | }); 67 | 68 | describe('when the ExportedConfig references an invalid builtin', function () { 69 | it('should fail', function () { 70 | // @ts-ignore 71 | const config = ['rtk:not-recommended']; 72 | expect( 73 | of(config).pipe( 74 | // @ts-ignore 75 | parseConfig() 76 | ), 77 | 'to emit error', 78 | {code: RTKERR_UNKNOWN_BUILTIN_CONFIG} 79 | ); 80 | }); 81 | }); 82 | 83 | describe('when the ExportedConfig is of an invalid format', function () { 84 | it('should fail', function () { 85 | // @ts-ignore 86 | const config = [[{wtf: 'is this'}]]; 87 | expect( 88 | of(config).pipe( 89 | // @ts-ignore 90 | parseConfig() 91 | ), 92 | 'to emit error', 93 | {code: RTKERR_INVALID_CONFIG, message: /config value/} 94 | ); 95 | }); 96 | }); 97 | 98 | describe('when the ExportedConfig contains an invalid key', function () { 99 | it('should fail', function () { 100 | // @ts-ignore 101 | const config = [{wtf: 'is this'}]; 102 | expect( 103 | of(config).pipe( 104 | // @ts-ignore 105 | parseConfig() 106 | ), 107 | 'to emit error', 108 | {code: RTKERR_INVALID_CONFIG, message: /config key/} 109 | ); 110 | }); 111 | }); 112 | }); 113 | }); 114 | }); 115 | -------------------------------------------------------------------------------- /packages/common/test/fixture/config/.rtkrc.js: -------------------------------------------------------------------------------- 1 | exports.config = [ 2 | 'rtk:recommended', 3 | { 4 | name: 'DEFAULT', 5 | rules: { 6 | 'long-timeout': ['on', {timeout: 4000}], 7 | 'library-mismatch': 'off' 8 | } 9 | } 10 | ]; 11 | -------------------------------------------------------------------------------- /packages/common/test/fixture/config/custom.config.js: -------------------------------------------------------------------------------- 1 | exports.config = [ 2 | 'rtk:recommended', 3 | { 4 | name: 'CUSTOM', 5 | rules: { 6 | 'library-mismatch': 'off', 7 | 'long-timeout': ['on', {timeout: 3000}] 8 | } 9 | } 10 | ]; 11 | -------------------------------------------------------------------------------- /packages/common/test/report.spec.js: -------------------------------------------------------------------------------- 1 | import {isReportLike} from '../src/report.js'; 2 | 3 | const REPORT_010_FILEPATH = require.resolve( 4 | './fixture/reports/report-010-win32.json' 5 | ); 6 | const REPORT_011_FILEPATH = require.resolve( 7 | './fixture/reports/report-011-missing-prop.json' 8 | ); 9 | const REPORT_002_FILEPATH = require.resolve( 10 | './fixture/reports/report-002-library-mismatch.json' 11 | ); 12 | const REPORT_001_FILEPATH = require.resolve( 13 | './fixture/reports/report-001.json' 14 | ); 15 | 16 | describe('@report-toolkit/common:report', function () { 17 | describe('class Report', function () { 18 | describe('static method', function () { 19 | describe('isReportLike', function () { 20 | it('should return `true` for a report generated on a win32 box (missing "userLimits")', function () { 21 | const report = require(REPORT_010_FILEPATH); 22 | expect(isReportLike(report), 'to be true'); 23 | }); 24 | 25 | it('should return `false` for a report otherwise missing a property', function () { 26 | const report = require(REPORT_011_FILEPATH); 27 | expect(isReportLike(report), 'to be false'); 28 | }); 29 | 30 | it('should return `true` for a pre-v2 report', function () { 31 | const report = require(REPORT_002_FILEPATH); 32 | expect(isReportLike(report), 'to be true'); 33 | }); 34 | 35 | it('should return `true` for a v2 report', function () { 36 | const report = require(REPORT_001_FILEPATH); 37 | expect(isReportLike(report), 'to be true'); 38 | }); 39 | }); 40 | }); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /packages/common/test/setup.js: -------------------------------------------------------------------------------- 1 | import './sinon-rxjs.js'; 2 | 3 | import proxyquire from 'proxyquire'; 4 | import sinon from 'sinon'; 5 | import unexpected from 'unexpected'; 6 | import * as unexpectedRxJS from 'unexpected-rxjs'; 7 | import unexpectedSinon from 'unexpected-sinon'; 8 | 9 | global.sinon = sinon; 10 | 11 | const expect = (global.expect = unexpected 12 | .clone() 13 | .use(unexpectedSinon) 14 | .use(unexpectedRxJS)); 15 | 16 | proxyquire.noPreserveCache(); 17 | 18 | global.proxyquire = proxyquire; 19 | 20 | expect.addAssertion( 21 | ' to (throw|throw error|throw exception) with code ', 22 | (expect, subject, code) => { 23 | return expect(subject, 'to throw', {code}); 24 | } 25 | ); 26 | -------------------------------------------------------------------------------- /packages/common/test/sinon-rxjs.js: -------------------------------------------------------------------------------- 1 | import {EMPTY, from, of, throwError} from 'rxjs'; 2 | import sinon from 'sinon'; 3 | 4 | const identity = value => value; 5 | 6 | sinon.addBehavior('returnsObservableOf', (fake, ...value) => { 7 | fake.returns(of(...value)); 8 | }); 9 | 10 | sinon.addBehavior('returnsObservableFrom', (fake, value = []) => { 11 | fake.returns(from(value)); 12 | }); 13 | 14 | sinon.addBehavior('returnsObservableError', (fake, value = new Error()) => { 15 | fake.returns(throwError(value)); 16 | }); 17 | 18 | sinon.addBehavior('returnsEmptyObservable', fake => { 19 | fake.returns(EMPTY); 20 | }); 21 | 22 | sinon.addBehavior( 23 | 'returnsOperatorFunction', 24 | (fake, pipe = identity, ...morePipes) => { 25 | fake.returns(observable => observable.pipe(pipe, ...morePipes)); 26 | } 27 | ); 28 | -------------------------------------------------------------------------------- /packages/core/.eslintignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | -------------------------------------------------------------------------------- /packages/core/LICENSE.md: -------------------------------------------------------------------------------- 1 | # Apache License, Version 2.0 (Apache-2.0) 2 | 3 | Copyright 2019 IBM, contributors 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 6 | this file except in compliance with the License. You may obtain a copy of the 7 | License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software distributed 12 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 13 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 14 | specific language governing permissions and limitations under the License. 15 | -------------------------------------------------------------------------------- /packages/core/README.md: -------------------------------------------------------------------------------- 1 | # report-toolkit 2 | 3 | See docs at [https://ibm.github.io/report-toolkit](https://ibm.github.io/report-toolkit) 4 | -------------------------------------------------------------------------------- /packages/core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@report-toolkit/core", 3 | "description": "", 4 | "version": "0.6.1", 5 | "author": "Christopher Hiller (https://boneskull.com/)", 6 | "dependencies": { 7 | "@report-toolkit/common": "^0.6.1", 8 | "@report-toolkit/diff": "^0.6.1", 9 | "@report-toolkit/inspector": "^0.6.1", 10 | "@report-toolkit/transformers": "^0.6.1", 11 | "resolve-from": "^5.0.0" 12 | }, 13 | "engines": { 14 | "node": ">=10" 15 | }, 16 | "files": [ 17 | "dist", 18 | "src" 19 | ], 20 | "keywords": [ 21 | "convert", 22 | "debug", 23 | "diagnose", 24 | "diagnostic", 25 | "diff", 26 | "inspect", 27 | "json", 28 | "node-report", 29 | "redact", 30 | "report", 31 | "sanitize", 32 | "secrets", 33 | "tool", 34 | "toolkit", 35 | "transform" 36 | ], 37 | "license": "Apache-2.0", 38 | "main": "dist/report-toolkit-core.cjs.js", 39 | "module": "src/index.js", 40 | "publishConfig": { 41 | "access": "public" 42 | }, 43 | "repository": "ibm/report-toolkit.git" 44 | } 45 | -------------------------------------------------------------------------------- /packages/core/test/fixture/plugins/baz/bar.js: -------------------------------------------------------------------------------- 1 | const REPORT_001_FILEPATH = require.resolve( 2 | '@report-toolkit/common/test/fixture/reports/report-001.json' 3 | ); 4 | 5 | export const inspect = () => context => { 6 | if (context.filepath !== REPORT_001_FILEPATH) { 7 | return 'bar'; 8 | } 9 | }; 10 | 11 | export const meta = {}; 12 | 13 | export const id = 'bar'; 14 | -------------------------------------------------------------------------------- /packages/core/test/fixture/plugins/baz/foo.js: -------------------------------------------------------------------------------- 1 | const REPORT_001_FILEPATH = require.resolve( 2 | '@report-toolkit/common/test/fixture/reports/report-001.json' 3 | ); 4 | 5 | export const inspect = () => context => { 6 | if (context.filepath === REPORT_001_FILEPATH) { 7 | return 'foo'; 8 | } 9 | }; 10 | 11 | export const meta = {}; 12 | 13 | export const id = 'foo'; 14 | -------------------------------------------------------------------------------- /packages/core/test/fixture/plugins/baz/index.js: -------------------------------------------------------------------------------- 1 | import * as bar from './bar.js'; 2 | import * as foo from './foo.js'; 3 | 4 | export const rules = [bar, foo]; 5 | -------------------------------------------------------------------------------- /packages/core/test/index.spec.js: -------------------------------------------------------------------------------- 1 | // @ts-ignore 2 | import REPORT_001 from '@report-toolkit/common/test/fixture/reports/report-001.json'; 3 | // @ts-ignore 4 | import REPORT_002 from '@report-toolkit/common/test/fixture/reports/report-002-library-mismatch.json'; 5 | 6 | describe('@report-toolkit/core', function () { 7 | let sandbox; 8 | let subject; 9 | 10 | beforeEach(function () { 11 | sandbox = sinon.createSandbox(); 12 | }); 13 | 14 | afterEach(function () { 15 | sandbox.restore(); 16 | }); 17 | 18 | describe('function', function () { 19 | let inspectStub; 20 | let diffStub; 21 | let loadConfigStub; 22 | let toReportFromObjectStub; 23 | 24 | beforeEach(function () { 25 | inspectStub = sandbox.stub().returnsObservableOf([]); 26 | diffStub = sandbox.stub().returnsObservableOf([]); 27 | toReportFromObjectStub = sandbox.stub().returnsOperatorFunction(); 28 | loadConfigStub = sandbox.stub().returnsObservableOf({}); 29 | subject = proxyquire(require.resolve('../src/index.js'), { 30 | './observable.js': { 31 | diff: diffStub, 32 | inspect: inspectStub, 33 | loadConfig: loadConfigStub, 34 | toReportFromObject: toReportFromObjectStub 35 | } 36 | }); 37 | }); 38 | 39 | describe('inspect()', function () { 40 | it('should delegate to observable.inspect()', async function () { 41 | await subject.inspect([REPORT_001, REPORT_002], []); 42 | expect(inspectStub, 'was called'); 43 | }); 44 | }); 45 | 46 | describe('diff()', function () { 47 | it('should delegate to observable.diff()', async function () { 48 | await subject.diff([REPORT_001, REPORT_002]); 49 | expect(diffStub, 'was called'); 50 | }); 51 | }); 52 | 53 | describe('loadConfig()', function () { 54 | it('should delegate to observable.loadConfig()', async function () { 55 | await subject.loadConfig({}); 56 | expect(loadConfigStub, 'was called'); 57 | }); 58 | }); 59 | 60 | describe('toReportFromObject()', function () { 61 | it('should delegate to observable.toReportFromObject()', async function () { 62 | await subject.toReportFromObject({}); 63 | expect(toReportFromObjectStub, 'was called'); 64 | }); 65 | }); 66 | }); 67 | }); 68 | -------------------------------------------------------------------------------- /packages/diff/.eslintignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | -------------------------------------------------------------------------------- /packages/diff/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [0.6.1](https://github.com/ibm/report-toolkit/compare/v0.6.0...v0.6.1) (2021-01-11) 7 | 8 | ### Bug Fixes 9 | 10 | - **diff:** update json-ptr due to semver violation in v1.3.x ([05deae8](https://github.com/ibm/report-toolkit/commit/05deae8cf0eeaa51d96c66a6c926b724e6e3a0d7)) 11 | 12 | # [0.6.0](https://github.com/ibm/report-toolkit/compare/v0.5.1...v0.6.0) (2020-02-25) 13 | 14 | **Note:** Version bump only for package @report-toolkit/diff 15 | 16 | ## [0.5.1](https://github.com/ibm/report-toolkit/compare/v0.5.0...v0.5.1) (2020-02-03) 17 | 18 | **Note:** Version bump only for package @report-toolkit/diff 19 | 20 | # [0.5.0](https://github.com/ibm/report-toolkit/compare/v0.4.1...v0.5.0) (2020-01-31) 21 | 22 | **Note:** Version bump only for package @report-toolkit/diff 23 | 24 | # [0.4.0](https://github.com/ibm/report-toolkit/compare/v0.3.0...v0.4.0) (2020-01-30) 25 | 26 | ### Bug Fixes 27 | 28 | - **diff:** rename 'path' to 'field' for consistency ([834ab9f](https://github.com/ibm/report-toolkit/commit/834ab9f7d8f4d4ea771e99b9d7eb1f3773c7e96f)) 29 | 30 | # [0.3.0](https://github.com/ibm/report-toolkit/compare/v0.2.3...v0.3.0) (2019-11-15) 31 | 32 | **Note:** Version bump only for package @report-toolkit/diff 33 | 34 | ## [0.2.3](https://github.com/ibm/report-toolkit/compare/v0.2.2...v0.2.3) (2019-11-13) 35 | 36 | **Note:** Version bump only for package @report-toolkit/diff 37 | 38 | ## [0.2.2](https://github.com/ibm/report-toolkit/compare/v0.2.1...v0.2.2) (2019-11-13) 39 | 40 | **Note:** Version bump only for package @report-toolkit/diff 41 | 42 | ## [0.2.1](https://github.com/ibm/report-toolkit/compare/v0.2.0...v0.2.1) (2019-11-07) 43 | 44 | **Note:** Version bump only for package @report-toolkit/diff 45 | 46 | # [0.2.0](https://github.com/ibm/report-toolkit/compare/v0.1.3...v0.2.0) (2019-10-25) 47 | 48 | **Note:** Version bump only for package @report-toolkit/diff 49 | 50 | ## [0.1.2](https://github.com/ibm/report-toolkit/compare/v0.1.1...v0.1.2) (2019-10-17) 51 | 52 | **Note:** Version bump only for package @report-toolkit/diff 53 | 54 | ## [0.1.1](https://github.com/ibm/report-toolkit/compare/v0.1.0...v0.1.1) (2019-10-17) 55 | 56 | **Note:** Version bump only for package @report-toolkit/diff 57 | 58 | # 0.1.0 (2019-10-17) 59 | 60 | ### Bug Fixes 61 | 62 | - **pkg:** linting/tests were broken ([9dc9ec6](https://github.com/ibm/report-toolkit/commit/9dc9ec662f4c688cf4eb7fb53839a3267f037539)) 63 | -------------------------------------------------------------------------------- /packages/diff/LICENSE.md: -------------------------------------------------------------------------------- 1 | # Apache License, Version 2.0 (Apache-2.0) 2 | 3 | Copyright 2019 IBM, contributors 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 6 | this file except in compliance with the License. You may obtain a copy of the 7 | License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software distributed 12 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 13 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 14 | specific language governing permissions and limitations under the License. 15 | -------------------------------------------------------------------------------- /packages/diff/README.md: -------------------------------------------------------------------------------- 1 | # report-toolkit 2 | 3 | See docs at [https://ibm.github.io/report-toolkit](https://ibm.github.io/report-toolkit) 4 | -------------------------------------------------------------------------------- /packages/diff/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@report-toolkit/diff", 3 | "version": "0.6.1", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@report-toolkit/common": { 8 | "version": "0.6.0", 9 | "resolved": "https://registry.npmjs.org/@report-toolkit/common/-/common-0.6.0.tgz", 10 | "integrity": "sha512-Fu3WQRjJtD/EO1i7J3AlO0YFHRv4lW6kDEjAUforDrT2hA/oJG+GkJWs9Pq4qmAbkMiU9+kAAke+6mwuyLW0rQ==", 11 | "requires": { 12 | "debug": "^4.1.1", 13 | "kleur": "^3.0.3", 14 | "lodash": "^4.17.15", 15 | "p-is-promise": "^3.0.0", 16 | "rxjs": "^6.5.4", 17 | "traverse": "^0.6.6" 18 | } 19 | }, 20 | "debug": { 21 | "version": "4.3.1", 22 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", 23 | "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", 24 | "requires": { 25 | "ms": "2.1.2" 26 | } 27 | }, 28 | "json-ptr": { 29 | "version": "2.0.0", 30 | "resolved": "https://registry.npmjs.org/json-ptr/-/json-ptr-2.0.0.tgz", 31 | "integrity": "sha512-VGP7ucQzBLJFUC8sWR57ALW/+iui9NCE2i61SULum4TBfu9664bCdWjuRkjghbg1rj1k+8+PciKbfFJdGQlS1w==", 32 | "requires": { 33 | "tslib": "^2.0.3" 34 | }, 35 | "dependencies": { 36 | "tslib": { 37 | "version": "2.1.0", 38 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", 39 | "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==" 40 | } 41 | } 42 | }, 43 | "kleur": { 44 | "version": "3.0.3", 45 | "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", 46 | "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==" 47 | }, 48 | "lodash": { 49 | "version": "4.17.20", 50 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", 51 | "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" 52 | }, 53 | "ms": { 54 | "version": "2.1.2", 55 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 56 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 57 | }, 58 | "p-is-promise": { 59 | "version": "3.0.0", 60 | "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-3.0.0.tgz", 61 | "integrity": "sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==" 62 | }, 63 | "rfc6902": { 64 | "version": "3.1.1", 65 | "resolved": "https://registry.npmjs.org/rfc6902/-/rfc6902-3.1.1.tgz", 66 | "integrity": "sha512-aHiEm2S4mQSyyIaK7NVotfmVkgOOn1K9iuuSCIKJ8eIAte/8o06Vp06Z2NcLrmMahDmA+2F6oHx33P4NOQ1JnQ==" 67 | }, 68 | "rxjs": { 69 | "version": "6.6.3", 70 | "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz", 71 | "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==", 72 | "requires": { 73 | "tslib": "^1.9.0" 74 | } 75 | }, 76 | "traverse": { 77 | "version": "0.6.6", 78 | "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz", 79 | "integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=" 80 | }, 81 | "tslib": { 82 | "version": "1.14.1", 83 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", 84 | "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /packages/diff/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@report-toolkit/diff", 3 | "description": "", 4 | "version": "0.6.1", 5 | "author": "Christopher Hiller (https://boneskull.com/)", 6 | "dependencies": { 7 | "@report-toolkit/common": "^0.6.1", 8 | "json-ptr": "^2.0.0", 9 | "rfc6902": "^3.1.1" 10 | }, 11 | "engines": { 12 | "node": ">=10" 13 | }, 14 | "files": [ 15 | "dist", 16 | "src" 17 | ], 18 | "keywords": [ 19 | "convert", 20 | "debug", 21 | "diagnose", 22 | "diagnostic", 23 | "diff", 24 | "inspect", 25 | "json", 26 | "node-report", 27 | "redact", 28 | "report", 29 | "sanitize", 30 | "secrets", 31 | "tool", 32 | "toolkit", 33 | "transform" 34 | ], 35 | "license": "Apache-2.0", 36 | "main": "dist/report-toolkit-diff.cjs.js", 37 | "module": "src/index.js", 38 | "publishConfig": { 39 | "access": "public" 40 | }, 41 | "repository": "ibm/report-toolkit.git" 42 | } 43 | -------------------------------------------------------------------------------- /packages/diff/test/index.spec.js: -------------------------------------------------------------------------------- 1 | import {DEFAULT_DIFF_EXCLUDE} from '@report-toolkit/common/src/constants.js'; 2 | import {of} from '@report-toolkit/common/src/observable.js'; 3 | // @ts-ignore 4 | import REPORT_DIFF from '@report-toolkit/common/test/fixture/diff/report-001-002.json'; 5 | // @ts-ignore 6 | import REPORT_1 from '@report-toolkit/common/test/fixture/reports/report-001.json'; 7 | // @ts-ignore 8 | import REPORT_2 from '@report-toolkit/common/test/fixture/reports/report-002-library-mismatch.json'; 9 | 10 | import {diff} from '../src/index.js'; 11 | 12 | describe('@report-toolkit/diff', function () { 13 | describe('function', function () { 14 | describe('diffReports()', function () { 15 | let source; 16 | 17 | beforeEach(function () { 18 | source = of([REPORT_1, REPORT_2]); 19 | }); 20 | 21 | it('should diff two reports using default properties', function () { 22 | return expect( 23 | source.pipe(diff()), 24 | 'to complete with values', 25 | ...REPORT_DIFF 26 | ); 27 | }); 28 | 29 | it('should not include omitted paths', function () { 30 | // XXX: yes, this is incredibly slow 31 | this.timeout(6000); 32 | this.slow(2250); 33 | return expect( 34 | source.pipe(diff()), 35 | 'not to complete with values satisfying', 36 | // @ts-ignore 37 | ...Array.from(DEFAULT_DIFF_EXCLUDE).map(field => ({field})) 38 | ); 39 | }); 40 | }); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /packages/docs/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [0.6.1](https://github.com/ibm/report-toolkit/compare/v0.6.0...v0.6.1) (2021-01-11) 7 | 8 | **Note:** Version bump only for package @report-toolkit/docs 9 | 10 | # [0.6.0](https://github.com/ibm/report-toolkit/compare/v0.5.1...v0.6.0) (2020-02-25) 11 | 12 | **Note:** Version bump only for package @report-toolkit/docs 13 | 14 | ## [0.5.1](https://github.com/ibm/report-toolkit/compare/v0.5.0...v0.5.1) (2020-02-03) 15 | 16 | **Note:** Version bump only for package @report-toolkit/docs 17 | 18 | # [0.5.0](https://github.com/ibm/report-toolkit/compare/v0.4.1...v0.5.0) (2020-01-31) 19 | 20 | **Note:** Version bump only for package @report-toolkit/docs 21 | 22 | # [0.4.0](https://github.com/ibm/report-toolkit/compare/v0.3.0...v0.4.0) (2020-01-30) 23 | 24 | **Note:** Version bump only for package @report-toolkit/docs 25 | 26 | # [0.3.0](https://github.com/ibm/report-toolkit/compare/v0.2.3...v0.3.0) (2019-11-15) 27 | 28 | **Note:** Version bump only for package @report-toolkit/docs 29 | 30 | ## [0.2.3](https://github.com/ibm/report-toolkit/compare/v0.2.2...v0.2.3) (2019-11-13) 31 | 32 | **Note:** Version bump only for package @report-toolkit/docs 33 | 34 | ## [0.2.2](https://github.com/ibm/report-toolkit/compare/v0.2.1...v0.2.2) (2019-11-13) 35 | 36 | **Note:** Version bump only for package @report-toolkit/docs 37 | 38 | ## [0.2.1](https://github.com/ibm/report-toolkit/compare/v0.2.0...v0.2.1) (2019-11-07) 39 | 40 | **Note:** Version bump only for package @report-toolkit/docs 41 | 42 | # [0.2.0](https://github.com/IBM/report-toolkit/compare/v0.1.3...v0.2.0) (2019-10-25) 43 | 44 | **Note:** Version bump only for package @report-toolkit/docs 45 | 46 | ## [0.1.2](https://github.com/IBM/report-toolkit/compare/v0.1.1...v0.1.2) (2019-10-17) 47 | 48 | **Note:** Version bump only for package @report-toolkit/docs 49 | 50 | # 0.1.0 (2019-10-17) 51 | 52 | ### Features 53 | 54 | - **docs:** add Breadcrumbs, Metadata & EmbedCode components for mdx ([a469109](https://github.com/IBM/report-toolkit/commit/a469109355105c341364295714c192c67fd0e173)) 55 | -------------------------------------------------------------------------------- /packages/docs/LICENSE.md: -------------------------------------------------------------------------------- 1 | # Apache License, Version 2.0 (Apache-2.0) 2 | 3 | Copyright 2019 IBM, contributors 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 6 | this file except in compliance with the License. You may obtain a copy of the 7 | License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software distributed 12 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 13 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 14 | specific language governing permissions and limitations under the License. 15 | -------------------------------------------------------------------------------- /packages/docs/README.md: -------------------------------------------------------------------------------- 1 | # report-toolkit 2 | 3 | See docs at [https://ibm.github.io/report-toolkit](https://ibm.github.io/report-toolkit) 4 | -------------------------------------------------------------------------------- /packages/docs/gatsby-browser.js: -------------------------------------------------------------------------------- 1 | import './src/styles/index.scss'; 2 | -------------------------------------------------------------------------------- /packages/docs/gatsby-config.js: -------------------------------------------------------------------------------- 1 | // @ts-ignore 2 | const {description, keywords} = require('./package.json'); 3 | const { 4 | NAMESPACE, 5 | SHORT_NAMESPACE 6 | } = require('@report-toolkit/common').constants; 7 | 8 | module.exports = { 9 | pathPrefix: '/report-toolkit', 10 | plugins: [ 11 | { 12 | options: { 13 | repository: { 14 | baseUrl: 'https://github.com/IBM/report-toolkit', 15 | subDirectory: 'packages/docs' 16 | }, 17 | titleType: 'append', 18 | gatsbyRemarkPlugins: ['gatsby-remark-import-code'] 19 | }, 20 | resolve: 'gatsby-theme-carbon' 21 | } 22 | ], 23 | siteMetadata: { 24 | description, 25 | executable: SHORT_NAMESPACE, 26 | keywords, 27 | packageName: NAMESPACE, 28 | title: `${NAMESPACE} for Node.js` 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /packages/docs/gatsby-node.js: -------------------------------------------------------------------------------- 1 | exports.onCreateNode = async function onCreateNode({ 2 | node, 3 | actions, 4 | loadNodeContent, 5 | createNodeId 6 | }) { 7 | const {createNode, createParentChildLink} = actions; 8 | 9 | // We only care about plain text content. 10 | if (node.internal.mediaType !== `text/plain`) { 11 | return; 12 | } 13 | 14 | const textNode = { 15 | id: createNodeId(`${node.id} >> TextFile`), 16 | parent: node.id, 17 | content: await loadNodeContent(node), 18 | name: node.name, 19 | internal: { 20 | contentDigest: node.internal.contentDigest, 21 | type: 'TextFile' 22 | } 23 | }; 24 | 25 | createNode(textNode); 26 | createParentChildLink({parent: node, child: textNode}); 27 | }; 28 | 29 | exports.sourceNodes = ({actions}) => { 30 | const {createTypes} = actions; 31 | 32 | if (createTypes) { 33 | createTypes(` 34 | type TextFile implements Node @infer @childOf(types: ["File"]) { 35 | id: ID! 36 | name: String! 37 | content: String! 38 | } 39 | `); 40 | } 41 | }; 42 | -------------------------------------------------------------------------------- /packages/docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@report-toolkit/docs", 3 | "description": "consumes Node.js diagnostic reports, outputs useful information", 4 | "version": "0.6.1", 5 | "author": "Christopher Hiller (https://boneskull.com/)", 6 | "devDependencies": { 7 | "@report-toolkit/common": "^0.6.1", 8 | "gatsby": "^2.19.10", 9 | "gatsby-remark-import-code": "^0.1.1", 10 | "gatsby-theme-carbon": "^1.20.0", 11 | "lodash": "^4.17.15", 12 | "react": "^16.12.0", 13 | "react-dom": "^16.12.0", 14 | "remark-plain-text": "^0.2.0" 15 | }, 16 | "engines": { 17 | "node": ">=10" 18 | }, 19 | "keywords": [ 20 | "convert", 21 | "debug", 22 | "diagnose", 23 | "diagnostic", 24 | "diff", 25 | "inspect", 26 | "json", 27 | "node-report", 28 | "redact", 29 | "report", 30 | "sanitize", 31 | "secrets", 32 | "tool", 33 | "toolkit", 34 | "transform" 35 | ], 36 | "license": "Apache-2.0", 37 | "private": true, 38 | "publishConfig": { 39 | "access": "public" 40 | }, 41 | "repository": "ibm/report-toolkit.git", 42 | "scripts": { 43 | "build": "gatsby build --prefix-paths", 44 | "build:netlify": "gatsby build", 45 | "dev": "gatsby develop", 46 | "dev:clean": "gatsby clean && gatsby develop", 47 | "serve": "gatsby serve" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /packages/docs/src/api.mdx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Here, you'll find documentation for 's public, programmatic API. 6 | 7 | If you want to use as a library or otherwise embed its functionalities into an app, these docs are for you. 8 | 9 | 10 | 11 | Below, you'll find an index of modules comprising the public API. 12 | 13 | 14 | 15 | At the time of this writing, the list below _does not_ contain the _entirety_ of this API--but it's enough to get started using as a library. 16 | 17 | 18 | 19 | **Hint:** Start with [@report-toolkit/core](/api/modules/report_toolkit_core)! 20 | 21 | ## Packages 22 | 23 | - [@report-toolkit/common](/api/modules/report_toolkit_common) 24 | - [@report-toolkit/core](/api/modules/report_toolkit_core) 25 | - [@report-toolkit/inspector](/api/modules/report-toolkit-inspector) 26 | -------------------------------------------------------------------------------- /packages/docs/src/components/index.js: -------------------------------------------------------------------------------- 1 | export {default as InlineCode} from './inline-code.js'; 2 | export {default as Metadata} from './metadata.js'; 3 | -------------------------------------------------------------------------------- /packages/docs/src/components/inline-code.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const InlineCode = ({children}) => { 4 | return {children}; 5 | }; 6 | 7 | export default InlineCode; 8 | -------------------------------------------------------------------------------- /packages/docs/src/components/metadata.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import useMetadata from '../gatsby-theme-carbon/util/hooks/useMetadata'; 4 | import InlineCode from './inline-code'; 5 | 6 | const Metadata = ({prop}) => { 7 | const metadata = useMetadata(); 8 | 9 | switch (prop) { 10 | case 'packageName': 11 | return {metadata[prop]}; 12 | case 'executable': 13 | return {metadata[prop]}; 14 | default: 15 | return <>{metadata[prop]}; 16 | } 17 | }; 18 | 19 | export default Metadata; 20 | -------------------------------------------------------------------------------- /packages/docs/src/data/nav-items.yaml: -------------------------------------------------------------------------------- 1 | - title: 'Quick Start' 2 | pages: 3 | - path: '/quick-start' 4 | title: 'Quick Start' 5 | - title: 'Command-Line Usage' 6 | pages: 7 | - path: '/cli' 8 | title: 'Command-Line Usage' 9 | - title: 'API Docs' 10 | pages: 11 | - path: '/api' 12 | title: 'API Docs' 13 | - title: 'Configuration' 14 | pages: 15 | - path: '/config' 16 | title: 'Configuration' 17 | -------------------------------------------------------------------------------- /packages/docs/src/gatsby-theme-carbon/components/Code/Code.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable react/jsx-key */ 2 | import cx from 'classnames'; 3 | import {Row} from 'gatsby-theme-carbon/src/components/Grid'; 4 | import Highlight, {defaultProps} from 'prism-react-renderer'; 5 | import React from 'react'; 6 | 7 | import { 8 | container, 9 | highlight, 10 | row, 11 | sideBarMinHeight, 12 | wordWrap 13 | } from './Code.module.scss'; 14 | import PathRow from './PathRow'; 15 | import prismTheme from './prismTheme'; 16 | import Sidebar from './Sidebar'; 17 | 18 | const Code = ({ 19 | children, 20 | className: classNameProp = '', 21 | path, 22 | src, 23 | wrap = false 24 | }) => { 25 | const language = classNameProp.replace(/language-/, ''); 26 | 27 | const removeTrailingEmptyLine = lines => { 28 | const [lastLine] = lines.splice(-1); 29 | if (lastLine[0].empty) { 30 | return lines; 31 | } 32 | return [...lines, lastLine]; 33 | }; 34 | 35 | return ( 36 | 37 | 38 | {children} 39 | 40 | 46 | {({className, style, tokens, getLineProps, getTokenProps}) => ( 47 |
48 |
56 |               {removeTrailingEmptyLine(tokens).map((line, i) => (
57 |                 
58 | {line.map((token, key) => ( 59 | 60 | ))} 61 |
62 | ))} 63 |
64 | 65 | {children} 66 | 67 |
68 | )} 69 |
70 |
71 | ); 72 | }; 73 | 74 | export default Code; 75 | -------------------------------------------------------------------------------- /packages/docs/src/gatsby-theme-carbon/components/Code/Code.module.scss: -------------------------------------------------------------------------------- 1 | :global { 2 | code { 3 | font-family: 'IBM Plex Mono', 'Menlo', 'DejaVu Sans Mono', 4 | 'Bitstream Vera Sans Mono', Courier, monospace; 5 | } 6 | 7 | p > code, 8 | li > code, 9 | td > code { 10 | @include carbon--type-style('code-01'); 11 | position: relative; 12 | display: inline; 13 | padding: 0 0.5em; 14 | font-size: 0.75em; 15 | bottom: 0.0625em; 16 | border-radius: 4px; 17 | background-color: $ui-03; 18 | color: $text-01; 19 | } 20 | 21 | // Add's additional length for scrolling under sidebar 22 | .token:last-of-type { 23 | margin-right: 64px; 24 | } 25 | } 26 | 27 | .wordWrap { 28 | white-space: pre-line; 29 | } 30 | 31 | .row { 32 | font-family: 'IBM Plex Mono', 'Menlo', 'DejaVu Sans Mono', 33 | 'Bitstream Vera Sans Mono', Courier, monospace; 34 | color: $inverse-01; 35 | @include carbon--type-style('code-02'); 36 | width: calc(100% + 2rem); 37 | @include carbon--breakpoint('lg') { 38 | width: calc(67% + 1rem); 39 | } 40 | } 41 | 42 | .container { 43 | position: relative; 44 | width: 100%; 45 | margin-bottom: $spacing-06; 46 | } 47 | 48 | .highlight { 49 | padding: $spacing-05; 50 | position: relative; 51 | overflow: auto; 52 | width: 100%; 53 | } 54 | 55 | .sideBarMinHeight { 56 | min-height: 96px; 57 | } 58 | 59 | // feedback tooltip adjustments 60 | .container :global(.bx--btn--copy__feedback) { 61 | position: absolute; 62 | &::before { 63 | left: $spacing-07; 64 | } 65 | &::after { 66 | left: $spacing-07; 67 | } 68 | &::before, 69 | &::after { 70 | z-index: z('floating'); 71 | } 72 | } 73 | 74 | .path-row { 75 | display: flex; 76 | align-items: center; 77 | justify-content: space-between; 78 | width: 100%; 79 | height: $spacing-09; 80 | background: $ui-05; 81 | padding-left: $spacing-05; 82 | padding-right: $spacing-03; 83 | border-bottom: 1px solid $inverse-02; 84 | } 85 | 86 | .sidebar { 87 | position: absolute; 88 | right: 0; 89 | top: 0; 90 | bottom: 16px; 91 | padding: 8px; 92 | padding-left: 32px; 93 | display: flex; 94 | flex-direction: column; 95 | align-items: center; 96 | overflow: visible; 97 | background: linear-gradient( 98 | 90deg, 99 | rgba(23, 23, 23, 0) 0%, 100 | rgba(23, 23, 23, 1) 24px 101 | ); 102 | } 103 | 104 | .sidebarWrapped { 105 | background: inherit; 106 | } 107 | 108 | // Copy button and src button 109 | .button, 110 | .copy-button.button { 111 | width: 32px; 112 | height: 32px; 113 | display: flex; 114 | justify-content: center; 115 | align-items: center; 116 | background: transparent; 117 | transition: background $duration--fast-02; 118 | z-index: 1000; 119 | &:hover { 120 | background-color: $inverse-02; 121 | } 122 | svg { 123 | fill: $inverse-01; 124 | } 125 | } 126 | 127 | .path-row .button { 128 | position: relative; 129 | right: 0; 130 | top: 0; 131 | } 132 | 133 | .sidebar .button { 134 | position: static; 135 | margin-bottom: $spacing-01; 136 | flex-shrink: 0; 137 | } 138 | -------------------------------------------------------------------------------- /packages/docs/src/gatsby-theme-carbon/components/Code/PathRow.js: -------------------------------------------------------------------------------- 1 | import {Launch16} from '@carbon/icons-react'; 2 | import {CopyButton} from 'carbon-components-react'; 3 | import cx from 'classnames'; 4 | import copy from 'copy-to-clipboard'; 5 | import React from 'react'; 6 | 7 | import {button, copyButton, pathRow} from './Code.module.scss'; 8 | 9 | // If no path is given, don't render. We'll use the Sidebar for buttons 10 | // If a src url is given, the src Icon will display in this row, otherwise 11 | // The copy button will. 12 | const PathRow = ({src, path, children}) => { 13 | if (!path) return null; 14 | return ( 15 |
16 | {path} 17 | {src ? ( 18 | 26 | 27 | 28 | ) : ( 29 | { 32 | copy(children); 33 | }} 34 | /> 35 | )} 36 |
37 | ); 38 | }; 39 | 40 | export default PathRow; 41 | -------------------------------------------------------------------------------- /packages/docs/src/gatsby-theme-carbon/components/Code/Sidebar.js: -------------------------------------------------------------------------------- 1 | import {Launch16} from '@carbon/icons-react'; 2 | import {CopyButton} from 'carbon-components-react'; 3 | import cx from 'classnames'; 4 | import copy from 'copy-to-clipboard'; 5 | import React from 'react'; 6 | 7 | // @ts-ignore 8 | import {button, copyButton, sidebar, sidebarWrapped} from './Code.module.scss'; 9 | 10 | // If there is a src url, but no path name, both icons appear in the sidebar. 11 | // If there is a path name, but no src url, the copy button should be in the PathRow 12 | // so we don't put it in the side bar. 13 | // 14 | // We'll still render the sidebar regardless of the path since we want the text fade. 15 | const Sidebar = ({src, path, children, wrap}) => { 16 | const shouldShowSrcLink = !path && src; 17 | const shouldShowCopyButton = !path || src; 18 | return ( 19 |
20 | {shouldShowCopyButton && ( 21 | { 24 | copy(children); 25 | }} 26 | /> 27 | )} 28 | {shouldShowSrcLink && ( 29 | 37 | 38 | 39 | )} 40 |
41 | ); 42 | }; 43 | 44 | export default Sidebar; 45 | -------------------------------------------------------------------------------- /packages/docs/src/gatsby-theme-carbon/components/Code/index.js: -------------------------------------------------------------------------------- 1 | import Code from './Code'; 2 | 3 | export default Code; 4 | -------------------------------------------------------------------------------- /packages/docs/src/gatsby-theme-carbon/components/Code/prismTheme.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | // Duotone Dark 3 | // Author: Simurai, adapted from DuoTone themes for Atom (http://simurai.com/projects/2016/01/01/duotone-themes) 4 | // Conversion: Bram de Haan (http://atelierbram.github.io/Base2Tone-prism/output/prism/prism-base2tone-evening-dark.css) 5 | // Generated with Base16 Builder (https://github.com/base16-builder/base16-builder) 6 | 7 | /* :: import type { PrismTheme } from '../src/types' */ 8 | import {ui05} from '@carbon/elements'; 9 | 10 | const theme /* : PrismTheme */ = { 11 | plain: { 12 | backgroundColor: ui05, 13 | color: '#fff' 14 | }, 15 | styles: [ 16 | { 17 | types: ['comment', 'prolog', 'doctype', 'cdata'], 18 | style: { 19 | color: '#bebebe' 20 | } 21 | }, 22 | { 23 | types: ['namespace'], 24 | style: { 25 | opacity: 0.7 26 | } 27 | }, 28 | { 29 | types: ['tag', 'operator'], 30 | style: { 31 | color: '#6ea6ff' 32 | } 33 | }, 34 | { 35 | types: ['property', 'function', 'attr-name'], 36 | style: { 37 | color: '#92eeee' 38 | } 39 | }, 40 | { 41 | types: ['variable'], 42 | style: { 43 | color: '#ffffff' 44 | } 45 | }, 46 | { 47 | types: ['string'], 48 | style: { 49 | color: '#fa75a6' 50 | } 51 | }, 52 | { 53 | types: ['entity'], 54 | style: { 55 | cursor: 'help' 56 | } 57 | }, 58 | { 59 | types: [ 60 | 'boolean', 61 | 'entity', 62 | 'url', 63 | 'attr-value', 64 | 'control', 65 | 'directive', 66 | 'unit', 67 | 'statement', 68 | 'regex', 69 | 'at-rule', 70 | 'selector', 71 | 'keyword', 72 | 'placeholder' 73 | ], 74 | style: { 75 | color: '#bb8eff' 76 | } 77 | }, 78 | { 79 | types: ['deleted'], 80 | style: { 81 | textDecorationLine: 'line-through' 82 | } 83 | }, 84 | { 85 | types: ['inserted'], 86 | style: { 87 | borderBottom: '1px dotted #c22dd5', 88 | textDecorationLine: 'underline' 89 | } 90 | }, 91 | { 92 | types: ['italic'], 93 | style: { 94 | fontStyle: 'italic' 95 | } 96 | }, 97 | { 98 | types: ['important', 'bold'], 99 | style: { 100 | fontWeight: 'bold' 101 | } 102 | }, 103 | { 104 | types: ['important'], 105 | style: { 106 | color: '#c94922' 107 | } 108 | } 109 | ] 110 | }; 111 | 112 | export default theme; 113 | -------------------------------------------------------------------------------- /packages/docs/src/gatsby-theme-carbon/components/Footer.js: -------------------------------------------------------------------------------- 1 | import Footer from 'gatsby-theme-carbon/src/components/Footer'; 2 | import React from 'react'; 3 | 4 | const Content = () => ( 5 | <> 6 |

7 | Have questions?{' '} 8 | 9 | Open an issue on GitHub 10 | 11 | .{' '} 12 |

13 |

14 | Built with{' '} 15 | 16 | Gatsby Theme Carbon 17 | 18 | . 19 |

20 |

21 | report-toolkit is licensed Apache-2.0 22 |

23 |

Copyright ©2019 IBM

24 | 25 | ); 26 | 27 | const links = { 28 | firstCol: [ 29 | {href: 'https://ibm.com/privacy', linkText: 'Privacy'}, 30 | {href: 'https://ibm.com/legal', linkText: 'Terms of Use'}, 31 | {href: 'https://ibm.com', linkText: 'IBM.com'} 32 | ], 33 | secondCol: [ 34 | {href: 'https://nodejs.org', linkText: 'NodeJS'}, 35 | {href: 'https://gatsbyjs.org', linkText: 'Gatsby'} 36 | ] 37 | }; 38 | 39 | const CustomFooter = () =>