├── .env.example ├── .github └── CODEOWNERS ├── .gitignore ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── assets ├── demonstration.png ├── logo.png └── logo.svg ├── docs ├── assets │ ├── anchor.js │ ├── bass-addons.css │ ├── bass.css │ ├── fonts │ │ ├── EOT │ │ │ ├── SourceCodePro-Bold.eot │ │ │ └── SourceCodePro-Regular.eot │ │ ├── LICENSE.txt │ │ ├── OTF │ │ │ ├── SourceCodePro-Bold.otf │ │ │ └── SourceCodePro-Regular.otf │ │ ├── TTF │ │ │ ├── SourceCodePro-Bold.ttf │ │ │ └── SourceCodePro-Regular.ttf │ │ ├── WOFF │ │ │ ├── OTF │ │ │ │ ├── SourceCodePro-Bold.otf.woff │ │ │ │ └── SourceCodePro-Regular.otf.woff │ │ │ └── TTF │ │ │ │ ├── SourceCodePro-Bold.ttf.woff │ │ │ │ └── SourceCodePro-Regular.ttf.woff │ │ ├── WOFF2 │ │ │ ├── OTF │ │ │ │ ├── SourceCodePro-Bold.otf.woff2 │ │ │ │ └── SourceCodePro-Regular.otf.woff2 │ │ │ └── TTF │ │ │ │ ├── SourceCodePro-Bold.ttf.woff2 │ │ │ │ └── SourceCodePro-Regular.ttf.woff2 │ │ └── source-code-pro.css │ ├── github.css │ ├── site.js │ ├── split.css │ ├── split.js │ └── style.css ├── ast │ └── source │ │ ├── .external-ecmascript.js.json │ │ ├── backgroundFinder.js.json │ │ ├── getPublicComments.js.json │ │ ├── github-api │ │ ├── createDiscussionIssue.js.json │ │ ├── getCommentsOnIssue.js.json │ │ ├── getUserCommentedIssues.js.json │ │ └── getUserDiscussionIssue.js.json │ │ └── utils │ │ ├── analyseSentiment.js.json │ │ ├── extractRepoDetailsFromUrl.js.json │ │ ├── filterUserComments.js.json │ │ └── getBinarySize.js.json ├── badge.svg ├── coverage.json ├── css │ ├── github.css │ ├── identifiers.css │ ├── manual.css │ ├── prettify-tomorrow.css │ ├── search.css │ ├── source.css │ ├── style.css │ └── test.css ├── file │ └── lib │ │ ├── backgroundFinder.js.html │ │ ├── getPublicComments.js.html │ │ ├── github-api │ │ ├── createDiscussionIssue.js.html │ │ ├── getCommentsOnIssue.js.html │ │ ├── getUserCommentedIssues.js.html │ │ └── getUserDiscussionIssue.js.html │ │ └── utils │ │ ├── analyseSentiment.js.html │ │ ├── extractRepoDetailsFromUrl.js.html │ │ ├── filterUserComments.js.html │ │ └── getBinarySize.js.html ├── identifiers.html ├── image │ ├── badge.svg │ ├── esdoc-logo-mini-black.png │ ├── esdoc-logo-mini.png │ ├── github.png │ ├── manual-badge.svg │ └── search.png ├── index.html ├── index.json ├── lint.json ├── script │ ├── inherited-summary.js │ ├── inner-link.js │ ├── manual.js │ ├── patch-for-local.js │ ├── prettify │ │ ├── Apache-License-2.0.txt │ │ └── prettify.js │ ├── pretty-print.js │ ├── search.js │ ├── search_index.js │ └── test-summary.js └── source.html ├── index.js ├── lib ├── backgroundFinder.js ├── discussionBoardSetup.js ├── getPublicComments.js ├── github-api │ ├── addCollaboratorToRepo.js │ ├── createDiscussionIssue.js │ ├── createDiscussionRepo.js │ ├── getCommentsOnIssue.js │ ├── getUserCommentedIssues.js │ └── getUserDiscussionIssue.js └── utils │ ├── analyseSentiment.js │ ├── extractRepoDetailsFromUrl.js │ └── filterUserComments.js ├── package.json ├── public └── wakemydyno.txt ├── scripts ├── simulate-watch.sh └── simulate.sh └── test ├── __snapshots__ ├── backgroundFinder.test.js.snap ├── createDiscussionIssue.test.js.snap ├── createDiscussionRepo.test.js.snap ├── discussionBoardSetup.test.js.snap ├── getUserCommentedIssues.test.js.snap └── getUserDiscussionIssue.test.js.snap ├── analyseSentiment.test.js ├── backgroundFinder.test.js ├── createDiscussionIssue.test.js ├── createDiscussionRepo.test.js ├── discussionBoardSetup.test.js ├── fixtures ├── installation.created.json ├── issue_comment.created.json ├── pull_request.opened.json └── sandbox.json ├── getUserCommentedIssues.test.js ├── getUserDiscussionIssue.test.js ├── index.test.js └── sandboxes ├── backgroundFinder.sandbox.js ├── createDiscussionIssue.sandbox.js ├── createDiscussionRepo.sandbox.js ├── discussionBoardSetup.sandbox.js ├── getCommentsOnIssue.sandbox.js ├── getPublicComments.sandbox.js ├── getUserCommentedIssues.sandbox.js ├── getUserDiscussionIssue.sandbox.js └── sandbox-runner.js /.env.example: -------------------------------------------------------------------------------- 1 | # The ID of your GitHub App 2 | APP_ID= 3 | WEBHOOK_SECRET=development 4 | 5 | # Use `trace` to get verbose logging or `info` to show less 6 | LOG_LEVEL=debug 7 | 8 | # Go to https://smee.io/new set this to the URL that you are redirected to. 9 | # WEBHOOK_PROXY_URL= 10 | PERSPECTIVE_API_KEY= 11 | GITHUB_ACCESS_TOKEN= 12 | APP_ORG_NAME='' 13 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @itaditya @bkeepers @JasonEtco 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | coverage 4 | *.pem 5 | .env 6 | package-lock.json 7 | *.ini 8 | *.log 9 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | education, socio-economic status, nationality, personal appearance, race, 10 | religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at {{{ email }}}. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Probot 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # background-check 2 | 3 | > A GitHub App built with [probot](https://github.com/probot/probot) that peforms a "background check" to identify users who have been toxic in the past, and shares their toxic activity in the maintainer’s discussion repo. 4 | 5 | [![Inline docs](http://inch-ci.org/github/probot/background-check.svg?branch=master)](http://inch-ci.org/github/probot/background-check) ![App Installations](https://img.shields.io/badge/dynamic/json.svg?label=Installations&url=https://probot-background-check.herokuapp.com/probot/stats&query=$.installations&colorB=2196F3&style=flat-green) 6 | 7 | ![Demo](assets/demonstration.png?raw=true) 8 | 9 | ## How to Use 10 | 11 | * Go to the [github app](https://github.com/apps/background-check) page. 12 | * Install the github app on your repos. 13 | * You'll get an invitation to a private repo, accept it and add other maintainers to the repo as well. 14 | 15 | ## FAQ 16 | 17 | ### 1. How does the bot finds the background? 18 | 19 | The bot listens to comments on repos in which the bot is installed. When a new user comments, the bot fetches public comments of this user and run sentiment analyser on them. If 5 or more comments stand out as toxic, then the bot concludes that the user is of hostile background and an issue is opened for this user in **probot-background-check/{your-name}-discussions** private repo so that the maintainers can review these toxic comments and discuss whether or not they will like to allow this hostile user to participate in their community. 20 | 21 | ### 2. What happens if the sentiment analysis is incorrect? 22 | 23 | In case of **false positives** where the sentiment analysis flags certain comments as toxic while they are not, the discussion issue would still be created. As the bot posts the toxic comments in the issue description, the maintainers can then verify the toxicity and then close the issue if they find the sentiment analysis incorrect. 24 | 25 | ### 3. Why does the app maintain a separate org for discussions? 26 | 27 | The discussion about a user who has been hostile in the past must ke kept private, so that only maintainers can see it. Because not every account (individual/org) has access to private repo, the app instead uses it's own org. Whenver the app is installed, a private repo for the maintainer's account gets created in the org and the installer is added as collaborator. This way discussions can be held privately. 28 | 29 | ## How To Contribute 30 | 31 | ### 1. Setup project in your development machine 32 | 33 | * Fork this repo. 34 | * Clone the forked repo in your development machine 35 | * `cd` into the repo directory, `cd background-check` probably. 36 | * Run `npm i` to setup project. 37 | 38 | ### 2. Setup Environment 39 | * Run `cp .env.example .env`. 40 | * Open `.env` file. 41 | * Generate [API key](https://github.com/conversationai/perspectiveapi/blob/master/quickstart.md) for Perspective API. 42 | * Paste this API key against `PERSPECTIVE_API_KEY` in `.env` file. 43 | * Create an org for the app. 44 | * Create a personal access token and paste that against `GITHUB_ACCESS_TOKEN` in `.env` file. 45 | * Create a Github App and follow [these](https://probot.github.io/docs/development/#configuring-a-github-app) instructions. 46 | 47 | **Do `npm start` to check if github app runs correctly in your dev machine. After this create branch, make changes, run tests, commit the changes and make a PR.** 48 | 49 | ## Common CLI commands 50 | 51 | To make the development of the project faster, these CLI commands are created. 52 | 53 | ```sh 54 | # Install dependencies 55 | npm install 56 | 57 | # Run the bot 58 | npm start 59 | 60 | # Run bot in dev mode which watches files for changes 61 | npm run dev 62 | 63 | # Run Unit Tests 64 | npm test 65 | 66 | # Run Unit Tests in watch mode 67 | npm run test:watch 68 | 69 | # Run linter and fix the issues 70 | npm run lint 71 | 72 | # Serve documentation locally 73 | npm run docs:serve 74 | 75 | # Run sandbox 76 | npm run sandbox -- --sandboxName 77 | 78 | Eg - npm run sandbox -- --getCommentsOnIssue 79 | ``` 80 | -------------------------------------------------------------------------------- /assets/demonstration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itaditya/background-check/dcfbe379d1618807b80696ce25d3771cabc64537/assets/demonstration.png -------------------------------------------------------------------------------- /assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itaditya/background-check/dcfbe379d1618807b80696ce25d3771cabc64537/assets/logo.png -------------------------------------------------------------------------------- /assets/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /docs/assets/bass-addons.css: -------------------------------------------------------------------------------- 1 | .input { 2 | font-family: inherit; 3 | display: block; 4 | width: 100%; 5 | height: 2rem; 6 | padding: .5rem; 7 | margin-bottom: 1rem; 8 | border: 1px solid #ccc; 9 | font-size: .875rem; 10 | border-radius: 3px; 11 | box-sizing: border-box; 12 | } 13 | -------------------------------------------------------------------------------- /docs/assets/bass.css: -------------------------------------------------------------------------------- 1 | /*! Basscss | http://basscss.com | MIT License */ 2 | 3 | .h1{ font-size: 2rem } 4 | .h2{ font-size: 1.5rem } 5 | .h3{ font-size: 1.25rem } 6 | .h4{ font-size: 1rem } 7 | .h5{ font-size: .875rem } 8 | .h6{ font-size: .75rem } 9 | 10 | .font-family-inherit{ font-family:inherit } 11 | .font-size-inherit{ font-size:inherit } 12 | .text-decoration-none{ text-decoration:none } 13 | 14 | .bold{ font-weight: bold; font-weight: bold } 15 | .regular{ font-weight:normal } 16 | .italic{ font-style:italic } 17 | .caps{ text-transform:uppercase; letter-spacing: .2em; } 18 | 19 | .left-align{ text-align:left } 20 | .center{ text-align:center } 21 | .right-align{ text-align:right } 22 | .justify{ text-align:justify } 23 | 24 | .nowrap{ white-space:nowrap } 25 | .break-word{ word-wrap:break-word } 26 | 27 | .line-height-1{ line-height: 1 } 28 | .line-height-2{ line-height: 1.125 } 29 | .line-height-3{ line-height: 1.25 } 30 | .line-height-4{ line-height: 1.5 } 31 | 32 | .list-style-none{ list-style:none } 33 | .underline{ text-decoration:underline } 34 | 35 | .truncate{ 36 | max-width:100%; 37 | overflow:hidden; 38 | text-overflow:ellipsis; 39 | white-space:nowrap; 40 | } 41 | 42 | .list-reset{ 43 | list-style:none; 44 | padding-left:0; 45 | } 46 | 47 | .inline{ display:inline } 48 | .block{ display:block } 49 | .inline-block{ display:inline-block } 50 | .table{ display:table } 51 | .table-cell{ display:table-cell } 52 | 53 | .overflow-hidden{ overflow:hidden } 54 | .overflow-scroll{ overflow:scroll } 55 | .overflow-auto{ overflow:auto } 56 | 57 | .clearfix:before, 58 | .clearfix:after{ 59 | content:" "; 60 | display:table 61 | } 62 | .clearfix:after{ clear:both } 63 | 64 | .left{ float:left } 65 | .right{ float:right } 66 | 67 | .fit{ max-width:100% } 68 | 69 | .max-width-1{ max-width: 24rem } 70 | .max-width-2{ max-width: 32rem } 71 | .max-width-3{ max-width: 48rem } 72 | .max-width-4{ max-width: 64rem } 73 | 74 | .border-box{ box-sizing:border-box } 75 | 76 | .align-baseline{ vertical-align:baseline } 77 | .align-top{ vertical-align:top } 78 | .align-middle{ vertical-align:middle } 79 | .align-bottom{ vertical-align:bottom } 80 | 81 | .m0{ margin:0 } 82 | .mt0{ margin-top:0 } 83 | .mr0{ margin-right:0 } 84 | .mb0{ margin-bottom:0 } 85 | .ml0{ margin-left:0 } 86 | .mx0{ margin-left:0; margin-right:0 } 87 | .my0{ margin-top:0; margin-bottom:0 } 88 | 89 | .m1{ margin: .5rem } 90 | .mt1{ margin-top: .5rem } 91 | .mr1{ margin-right: .5rem } 92 | .mb1{ margin-bottom: .5rem } 93 | .ml1{ margin-left: .5rem } 94 | .mx1{ margin-left: .5rem; margin-right: .5rem } 95 | .my1{ margin-top: .5rem; margin-bottom: .5rem } 96 | 97 | .m2{ margin: 1rem } 98 | .mt2{ margin-top: 1rem } 99 | .mr2{ margin-right: 1rem } 100 | .mb2{ margin-bottom: 1rem } 101 | .ml2{ margin-left: 1rem } 102 | .mx2{ margin-left: 1rem; margin-right: 1rem } 103 | .my2{ margin-top: 1rem; margin-bottom: 1rem } 104 | 105 | .m3{ margin: 2rem } 106 | .mt3{ margin-top: 2rem } 107 | .mr3{ margin-right: 2rem } 108 | .mb3{ margin-bottom: 2rem } 109 | .ml3{ margin-left: 2rem } 110 | .mx3{ margin-left: 2rem; margin-right: 2rem } 111 | .my3{ margin-top: 2rem; margin-bottom: 2rem } 112 | 113 | .m4{ margin: 4rem } 114 | .mt4{ margin-top: 4rem } 115 | .mr4{ margin-right: 4rem } 116 | .mb4{ margin-bottom: 4rem } 117 | .ml4{ margin-left: 4rem } 118 | .mx4{ margin-left: 4rem; margin-right: 4rem } 119 | .my4{ margin-top: 4rem; margin-bottom: 4rem } 120 | 121 | .mxn1{ margin-left: -.5rem; margin-right: -.5rem; } 122 | .mxn2{ margin-left: -1rem; margin-right: -1rem; } 123 | .mxn3{ margin-left: -2rem; margin-right: -2rem; } 124 | .mxn4{ margin-left: -4rem; margin-right: -4rem; } 125 | 126 | .ml-auto{ margin-left:auto } 127 | .mr-auto{ margin-right:auto } 128 | .mx-auto{ margin-left:auto; margin-right:auto; } 129 | 130 | .p0{ padding:0 } 131 | .pt0{ padding-top:0 } 132 | .pr0{ padding-right:0 } 133 | .pb0{ padding-bottom:0 } 134 | .pl0{ padding-left:0 } 135 | .px0{ padding-left:0; padding-right:0 } 136 | .py0{ padding-top:0; padding-bottom:0 } 137 | 138 | .p1{ padding: .5rem } 139 | .pt1{ padding-top: .5rem } 140 | .pr1{ padding-right: .5rem } 141 | .pb1{ padding-bottom: .5rem } 142 | .pl1{ padding-left: .5rem } 143 | .py1{ padding-top: .5rem; padding-bottom: .5rem } 144 | .px1{ padding-left: .5rem; padding-right: .5rem } 145 | 146 | .p2{ padding: 1rem } 147 | .pt2{ padding-top: 1rem } 148 | .pr2{ padding-right: 1rem } 149 | .pb2{ padding-bottom: 1rem } 150 | .pl2{ padding-left: 1rem } 151 | .py2{ padding-top: 1rem; padding-bottom: 1rem } 152 | .px2{ padding-left: 1rem; padding-right: 1rem } 153 | 154 | .p3{ padding: 2rem } 155 | .pt3{ padding-top: 2rem } 156 | .pr3{ padding-right: 2rem } 157 | .pb3{ padding-bottom: 2rem } 158 | .pl3{ padding-left: 2rem } 159 | .py3{ padding-top: 2rem; padding-bottom: 2rem } 160 | .px3{ padding-left: 2rem; padding-right: 2rem } 161 | 162 | .p4{ padding: 4rem } 163 | .pt4{ padding-top: 4rem } 164 | .pr4{ padding-right: 4rem } 165 | .pb4{ padding-bottom: 4rem } 166 | .pl4{ padding-left: 4rem } 167 | .py4{ padding-top: 4rem; padding-bottom: 4rem } 168 | .px4{ padding-left: 4rem; padding-right: 4rem } 169 | 170 | .col{ 171 | float:left; 172 | box-sizing:border-box; 173 | } 174 | 175 | .col-right{ 176 | float:right; 177 | box-sizing:border-box; 178 | } 179 | 180 | .col-1{ 181 | width:8.33333%; 182 | } 183 | 184 | .col-2{ 185 | width:16.66667%; 186 | } 187 | 188 | .col-3{ 189 | width:25%; 190 | } 191 | 192 | .col-4{ 193 | width:33.33333%; 194 | } 195 | 196 | .col-5{ 197 | width:41.66667%; 198 | } 199 | 200 | .col-6{ 201 | width:50%; 202 | } 203 | 204 | .col-7{ 205 | width:58.33333%; 206 | } 207 | 208 | .col-8{ 209 | width:66.66667%; 210 | } 211 | 212 | .col-9{ 213 | width:75%; 214 | } 215 | 216 | .col-10{ 217 | width:83.33333%; 218 | } 219 | 220 | .col-11{ 221 | width:91.66667%; 222 | } 223 | 224 | .col-12{ 225 | width:100%; 226 | } 227 | @media (min-width: 40em){ 228 | 229 | .sm-col{ 230 | float:left; 231 | box-sizing:border-box; 232 | } 233 | 234 | .sm-col-right{ 235 | float:right; 236 | box-sizing:border-box; 237 | } 238 | 239 | .sm-col-1{ 240 | width:8.33333%; 241 | } 242 | 243 | .sm-col-2{ 244 | width:16.66667%; 245 | } 246 | 247 | .sm-col-3{ 248 | width:25%; 249 | } 250 | 251 | .sm-col-4{ 252 | width:33.33333%; 253 | } 254 | 255 | .sm-col-5{ 256 | width:41.66667%; 257 | } 258 | 259 | .sm-col-6{ 260 | width:50%; 261 | } 262 | 263 | .sm-col-7{ 264 | width:58.33333%; 265 | } 266 | 267 | .sm-col-8{ 268 | width:66.66667%; 269 | } 270 | 271 | .sm-col-9{ 272 | width:75%; 273 | } 274 | 275 | .sm-col-10{ 276 | width:83.33333%; 277 | } 278 | 279 | .sm-col-11{ 280 | width:91.66667%; 281 | } 282 | 283 | .sm-col-12{ 284 | width:100%; 285 | } 286 | 287 | } 288 | @media (min-width: 52em){ 289 | 290 | .md-col{ 291 | float:left; 292 | box-sizing:border-box; 293 | } 294 | 295 | .md-col-right{ 296 | float:right; 297 | box-sizing:border-box; 298 | } 299 | 300 | .md-col-1{ 301 | width:8.33333%; 302 | } 303 | 304 | .md-col-2{ 305 | width:16.66667%; 306 | } 307 | 308 | .md-col-3{ 309 | width:25%; 310 | } 311 | 312 | .md-col-4{ 313 | width:33.33333%; 314 | } 315 | 316 | .md-col-5{ 317 | width:41.66667%; 318 | } 319 | 320 | .md-col-6{ 321 | width:50%; 322 | } 323 | 324 | .md-col-7{ 325 | width:58.33333%; 326 | } 327 | 328 | .md-col-8{ 329 | width:66.66667%; 330 | } 331 | 332 | .md-col-9{ 333 | width:75%; 334 | } 335 | 336 | .md-col-10{ 337 | width:83.33333%; 338 | } 339 | 340 | .md-col-11{ 341 | width:91.66667%; 342 | } 343 | 344 | .md-col-12{ 345 | width:100%; 346 | } 347 | 348 | } 349 | @media (min-width: 64em){ 350 | 351 | .lg-col{ 352 | float:left; 353 | box-sizing:border-box; 354 | } 355 | 356 | .lg-col-right{ 357 | float:right; 358 | box-sizing:border-box; 359 | } 360 | 361 | .lg-col-1{ 362 | width:8.33333%; 363 | } 364 | 365 | .lg-col-2{ 366 | width:16.66667%; 367 | } 368 | 369 | .lg-col-3{ 370 | width:25%; 371 | } 372 | 373 | .lg-col-4{ 374 | width:33.33333%; 375 | } 376 | 377 | .lg-col-5{ 378 | width:41.66667%; 379 | } 380 | 381 | .lg-col-6{ 382 | width:50%; 383 | } 384 | 385 | .lg-col-7{ 386 | width:58.33333%; 387 | } 388 | 389 | .lg-col-8{ 390 | width:66.66667%; 391 | } 392 | 393 | .lg-col-9{ 394 | width:75%; 395 | } 396 | 397 | .lg-col-10{ 398 | width:83.33333%; 399 | } 400 | 401 | .lg-col-11{ 402 | width:91.66667%; 403 | } 404 | 405 | .lg-col-12{ 406 | width:100%; 407 | } 408 | 409 | } 410 | .flex{ display:-webkit-box; display:-webkit-flex; display:-ms-flexbox; display:flex } 411 | 412 | @media (min-width: 40em){ 413 | .sm-flex{ display:-webkit-box; display:-webkit-flex; display:-ms-flexbox; display:flex } 414 | } 415 | 416 | @media (min-width: 52em){ 417 | .md-flex{ display:-webkit-box; display:-webkit-flex; display:-ms-flexbox; display:flex } 418 | } 419 | 420 | @media (min-width: 64em){ 421 | .lg-flex{ display:-webkit-box; display:-webkit-flex; display:-ms-flexbox; display:flex } 422 | } 423 | 424 | .flex-column{ -webkit-box-orient:vertical; -webkit-box-direction:normal; -webkit-flex-direction:column; -ms-flex-direction:column; flex-direction:column } 425 | .flex-wrap{ -webkit-flex-wrap:wrap; -ms-flex-wrap:wrap; flex-wrap:wrap } 426 | 427 | .items-start{ -webkit-box-align:start; -webkit-align-items:flex-start; -ms-flex-align:start; -ms-grid-row-align:flex-start; align-items:flex-start } 428 | .items-end{ -webkit-box-align:end; -webkit-align-items:flex-end; -ms-flex-align:end; -ms-grid-row-align:flex-end; align-items:flex-end } 429 | .items-center{ -webkit-box-align:center; -webkit-align-items:center; -ms-flex-align:center; -ms-grid-row-align:center; align-items:center } 430 | .items-baseline{ -webkit-box-align:baseline; -webkit-align-items:baseline; -ms-flex-align:baseline; -ms-grid-row-align:baseline; align-items:baseline } 431 | .items-stretch{ -webkit-box-align:stretch; -webkit-align-items:stretch; -ms-flex-align:stretch; -ms-grid-row-align:stretch; align-items:stretch } 432 | 433 | .self-start{ -webkit-align-self:flex-start; -ms-flex-item-align:start; align-self:flex-start } 434 | .self-end{ -webkit-align-self:flex-end; -ms-flex-item-align:end; align-self:flex-end } 435 | .self-center{ -webkit-align-self:center; -ms-flex-item-align:center; align-self:center } 436 | .self-baseline{ -webkit-align-self:baseline; -ms-flex-item-align:baseline; align-self:baseline } 437 | .self-stretch{ -webkit-align-self:stretch; -ms-flex-item-align:stretch; align-self:stretch } 438 | 439 | .justify-start{ -webkit-box-pack:start; -webkit-justify-content:flex-start; -ms-flex-pack:start; justify-content:flex-start } 440 | .justify-end{ -webkit-box-pack:end; -webkit-justify-content:flex-end; -ms-flex-pack:end; justify-content:flex-end } 441 | .justify-center{ -webkit-box-pack:center; -webkit-justify-content:center; -ms-flex-pack:center; justify-content:center } 442 | .justify-between{ -webkit-box-pack:justify; -webkit-justify-content:space-between; -ms-flex-pack:justify; justify-content:space-between } 443 | .justify-around{ -webkit-justify-content:space-around; -ms-flex-pack:distribute; justify-content:space-around } 444 | 445 | .content-start{ -webkit-align-content:flex-start; -ms-flex-line-pack:start; align-content:flex-start } 446 | .content-end{ -webkit-align-content:flex-end; -ms-flex-line-pack:end; align-content:flex-end } 447 | .content-center{ -webkit-align-content:center; -ms-flex-line-pack:center; align-content:center } 448 | .content-between{ -webkit-align-content:space-between; -ms-flex-line-pack:justify; align-content:space-between } 449 | .content-around{ -webkit-align-content:space-around; -ms-flex-line-pack:distribute; align-content:space-around } 450 | .content-stretch{ -webkit-align-content:stretch; -ms-flex-line-pack:stretch; align-content:stretch } 451 | .flex-auto{ 452 | -webkit-box-flex:1; 453 | -webkit-flex:1 1 auto; 454 | -ms-flex:1 1 auto; 455 | flex:1 1 auto; 456 | min-width:0; 457 | min-height:0; 458 | } 459 | .flex-none{ -webkit-box-flex:0; -webkit-flex:none; -ms-flex:none; flex:none } 460 | .fs0{ flex-shrink: 0 } 461 | 462 | .order-0{ -webkit-box-ordinal-group:1; -webkit-order:0; -ms-flex-order:0; order:0 } 463 | .order-1{ -webkit-box-ordinal-group:2; -webkit-order:1; -ms-flex-order:1; order:1 } 464 | .order-2{ -webkit-box-ordinal-group:3; -webkit-order:2; -ms-flex-order:2; order:2 } 465 | .order-3{ -webkit-box-ordinal-group:4; -webkit-order:3; -ms-flex-order:3; order:3 } 466 | .order-last{ -webkit-box-ordinal-group:100000; -webkit-order:99999; -ms-flex-order:99999; order:99999 } 467 | 468 | .relative{ position:relative } 469 | .absolute{ position:absolute } 470 | .fixed{ position:fixed } 471 | 472 | .top-0{ top:0 } 473 | .right-0{ right:0 } 474 | .bottom-0{ bottom:0 } 475 | .left-0{ left:0 } 476 | 477 | .z1{ z-index: 1 } 478 | .z2{ z-index: 2 } 479 | .z3{ z-index: 3 } 480 | .z4{ z-index: 4 } 481 | 482 | .border{ 483 | border-style:solid; 484 | border-width: 1px; 485 | } 486 | 487 | .border-top{ 488 | border-top-style:solid; 489 | border-top-width: 1px; 490 | } 491 | 492 | .border-right{ 493 | border-right-style:solid; 494 | border-right-width: 1px; 495 | } 496 | 497 | .border-bottom{ 498 | border-bottom-style:solid; 499 | border-bottom-width: 1px; 500 | } 501 | 502 | .border-left{ 503 | border-left-style:solid; 504 | border-left-width: 1px; 505 | } 506 | 507 | .border-none{ border:0 } 508 | 509 | .rounded{ border-radius: 3px } 510 | .circle{ border-radius:50% } 511 | 512 | .rounded-top{ border-radius: 3px 3px 0 0 } 513 | .rounded-right{ border-radius: 0 3px 3px 0 } 514 | .rounded-bottom{ border-radius: 0 0 3px 3px } 515 | .rounded-left{ border-radius: 3px 0 0 3px } 516 | 517 | .not-rounded{ border-radius:0 } 518 | 519 | .hide{ 520 | position:absolute !important; 521 | height:1px; 522 | width:1px; 523 | overflow:hidden; 524 | clip:rect(1px, 1px, 1px, 1px); 525 | } 526 | 527 | @media (max-width: 40em){ 528 | .xs-hide{ display:none !important } 529 | } 530 | 531 | @media (min-width: 40em) and (max-width: 52em){ 532 | .sm-hide{ display:none !important } 533 | } 534 | 535 | @media (min-width: 52em) and (max-width: 64em){ 536 | .md-hide{ display:none !important } 537 | } 538 | 539 | @media (min-width: 64em){ 540 | .lg-hide{ display:none !important } 541 | } 542 | 543 | .display-none{ display:none !important } 544 | 545 | -------------------------------------------------------------------------------- /docs/assets/fonts/EOT/SourceCodePro-Bold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itaditya/background-check/dcfbe379d1618807b80696ce25d3771cabc64537/docs/assets/fonts/EOT/SourceCodePro-Bold.eot -------------------------------------------------------------------------------- /docs/assets/fonts/EOT/SourceCodePro-Regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itaditya/background-check/dcfbe379d1618807b80696ce25d3771cabc64537/docs/assets/fonts/EOT/SourceCodePro-Regular.eot -------------------------------------------------------------------------------- /docs/assets/fonts/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries. 2 | 3 | This Font Software is licensed under the SIL Open Font License, Version 1.1. 4 | 5 | This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL 6 | 7 | 8 | ----------------------------------------------------------- 9 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 10 | ----------------------------------------------------------- 11 | 12 | PREAMBLE 13 | The goals of the Open Font License (OFL) are to stimulate worldwide 14 | development of collaborative font projects, to support the font creation 15 | efforts of academic and linguistic communities, and to provide a free and 16 | open framework in which fonts may be shared and improved in partnership 17 | with others. 18 | 19 | The OFL allows the licensed fonts to be used, studied, modified and 20 | redistributed freely as long as they are not sold by themselves. The 21 | fonts, including any derivative works, can be bundled, embedded, 22 | redistributed and/or sold with any software provided that any reserved 23 | names are not used by derivative works. The fonts and derivatives, 24 | however, cannot be released under any other type of license. The 25 | requirement for fonts to remain under this license does not apply 26 | to any document created using the fonts or their derivatives. 27 | 28 | DEFINITIONS 29 | "Font Software" refers to the set of files released by the Copyright 30 | Holder(s) under this license and clearly marked as such. This may 31 | include source files, build scripts and documentation. 32 | 33 | "Reserved Font Name" refers to any names specified as such after the 34 | copyright statement(s). 35 | 36 | "Original Version" refers to the collection of Font Software components as 37 | distributed by the Copyright Holder(s). 38 | 39 | "Modified Version" refers to any derivative made by adding to, deleting, 40 | or substituting -- in part or in whole -- any of the components of the 41 | Original Version, by changing formats or by porting the Font Software to a 42 | new environment. 43 | 44 | "Author" refers to any designer, engineer, programmer, technical 45 | writer or other person who contributed to the Font Software. 46 | 47 | PERMISSION & CONDITIONS 48 | Permission is hereby granted, free of charge, to any person obtaining 49 | a copy of the Font Software, to use, study, copy, merge, embed, modify, 50 | redistribute, and sell modified and unmodified copies of the Font 51 | Software, subject to the following conditions: 52 | 53 | 1) Neither the Font Software nor any of its individual components, 54 | in Original or Modified Versions, may be sold by itself. 55 | 56 | 2) Original or Modified Versions of the Font Software may be bundled, 57 | redistributed and/or sold with any software, provided that each copy 58 | contains the above copyright notice and this license. These can be 59 | included either as stand-alone text files, human-readable headers or 60 | in the appropriate machine-readable metadata fields within text or 61 | binary files as long as those fields can be easily viewed by the user. 62 | 63 | 3) No Modified Version of the Font Software may use the Reserved Font 64 | Name(s) unless explicit written permission is granted by the corresponding 65 | Copyright Holder. This restriction only applies to the primary font name as 66 | presented to the users. 67 | 68 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 69 | Software shall not be used to promote, endorse or advertise any 70 | Modified Version, except to acknowledge the contribution(s) of the 71 | Copyright Holder(s) and the Author(s) or with their explicit written 72 | permission. 73 | 74 | 5) The Font Software, modified or unmodified, in part or in whole, 75 | must be distributed entirely under this license, and must not be 76 | distributed under any other license. The requirement for fonts to 77 | remain under this license does not apply to any document created 78 | using the Font Software. 79 | 80 | TERMINATION 81 | This license becomes null and void if any of the above conditions are 82 | not met. 83 | 84 | DISCLAIMER 85 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 86 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 87 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 88 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 89 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 90 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 91 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 92 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 93 | OTHER DEALINGS IN THE FONT SOFTWARE. 94 | -------------------------------------------------------------------------------- /docs/assets/fonts/OTF/SourceCodePro-Bold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itaditya/background-check/dcfbe379d1618807b80696ce25d3771cabc64537/docs/assets/fonts/OTF/SourceCodePro-Bold.otf -------------------------------------------------------------------------------- /docs/assets/fonts/OTF/SourceCodePro-Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itaditya/background-check/dcfbe379d1618807b80696ce25d3771cabc64537/docs/assets/fonts/OTF/SourceCodePro-Regular.otf -------------------------------------------------------------------------------- /docs/assets/fonts/TTF/SourceCodePro-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itaditya/background-check/dcfbe379d1618807b80696ce25d3771cabc64537/docs/assets/fonts/TTF/SourceCodePro-Bold.ttf -------------------------------------------------------------------------------- /docs/assets/fonts/TTF/SourceCodePro-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itaditya/background-check/dcfbe379d1618807b80696ce25d3771cabc64537/docs/assets/fonts/TTF/SourceCodePro-Regular.ttf -------------------------------------------------------------------------------- /docs/assets/fonts/WOFF/OTF/SourceCodePro-Bold.otf.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itaditya/background-check/dcfbe379d1618807b80696ce25d3771cabc64537/docs/assets/fonts/WOFF/OTF/SourceCodePro-Bold.otf.woff -------------------------------------------------------------------------------- /docs/assets/fonts/WOFF/OTF/SourceCodePro-Regular.otf.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itaditya/background-check/dcfbe379d1618807b80696ce25d3771cabc64537/docs/assets/fonts/WOFF/OTF/SourceCodePro-Regular.otf.woff -------------------------------------------------------------------------------- /docs/assets/fonts/WOFF/TTF/SourceCodePro-Bold.ttf.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itaditya/background-check/dcfbe379d1618807b80696ce25d3771cabc64537/docs/assets/fonts/WOFF/TTF/SourceCodePro-Bold.ttf.woff -------------------------------------------------------------------------------- /docs/assets/fonts/WOFF/TTF/SourceCodePro-Regular.ttf.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itaditya/background-check/dcfbe379d1618807b80696ce25d3771cabc64537/docs/assets/fonts/WOFF/TTF/SourceCodePro-Regular.ttf.woff -------------------------------------------------------------------------------- /docs/assets/fonts/WOFF2/OTF/SourceCodePro-Bold.otf.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itaditya/background-check/dcfbe379d1618807b80696ce25d3771cabc64537/docs/assets/fonts/WOFF2/OTF/SourceCodePro-Bold.otf.woff2 -------------------------------------------------------------------------------- /docs/assets/fonts/WOFF2/OTF/SourceCodePro-Regular.otf.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itaditya/background-check/dcfbe379d1618807b80696ce25d3771cabc64537/docs/assets/fonts/WOFF2/OTF/SourceCodePro-Regular.otf.woff2 -------------------------------------------------------------------------------- /docs/assets/fonts/WOFF2/TTF/SourceCodePro-Bold.ttf.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itaditya/background-check/dcfbe379d1618807b80696ce25d3771cabc64537/docs/assets/fonts/WOFF2/TTF/SourceCodePro-Bold.ttf.woff2 -------------------------------------------------------------------------------- /docs/assets/fonts/WOFF2/TTF/SourceCodePro-Regular.ttf.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itaditya/background-check/dcfbe379d1618807b80696ce25d3771cabc64537/docs/assets/fonts/WOFF2/TTF/SourceCodePro-Regular.ttf.woff2 -------------------------------------------------------------------------------- /docs/assets/fonts/source-code-pro.css: -------------------------------------------------------------------------------- 1 | @font-face{ 2 | font-family: 'Source Code Pro'; 3 | font-weight: 400; 4 | font-style: normal; 5 | font-stretch: normal; 6 | src: url('EOT/SourceCodePro-Regular.eot') format('embedded-opentype'), 7 | url('WOFF2/TTF/SourceCodePro-Regular.ttf.woff2') format('woff2'), 8 | url('WOFF/OTF/SourceCodePro-Regular.otf.woff') format('woff'), 9 | url('OTF/SourceCodePro-Regular.otf') format('opentype'), 10 | url('TTF/SourceCodePro-Regular.ttf') format('truetype'); 11 | } 12 | 13 | @font-face{ 14 | font-family: 'Source Code Pro'; 15 | font-weight: 700; 16 | font-style: normal; 17 | font-stretch: normal; 18 | src: url('EOT/SourceCodePro-Bold.eot') format('embedded-opentype'), 19 | url('WOFF2/TTF/SourceCodePro-Bold.ttf.woff2') format('woff2'), 20 | url('WOFF/OTF/SourceCodePro-Bold.otf.woff') format('woff'), 21 | url('OTF/SourceCodePro-Bold.otf') format('opentype'), 22 | url('TTF/SourceCodePro-Bold.ttf') format('truetype'); 23 | } 24 | -------------------------------------------------------------------------------- /docs/assets/github.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | github.com style (c) Vasily Polovnyov 4 | 5 | */ 6 | 7 | .hljs { 8 | display: block; 9 | overflow-x: auto; 10 | padding: 0.5em; 11 | color: #333; 12 | background: #f8f8f8; 13 | -webkit-text-size-adjust: none; 14 | } 15 | 16 | .hljs-comment, 17 | .diff .hljs-header, 18 | .hljs-javadoc { 19 | color: #998; 20 | font-style: italic; 21 | } 22 | 23 | .hljs-keyword, 24 | .css .rule .hljs-keyword, 25 | .hljs-winutils, 26 | .nginx .hljs-title, 27 | .hljs-subst, 28 | .hljs-request, 29 | .hljs-status { 30 | color: #1184CE; 31 | } 32 | 33 | .hljs-number, 34 | .hljs-hexcolor, 35 | .ruby .hljs-constant { 36 | color: #ed225d; 37 | } 38 | 39 | .hljs-string, 40 | .hljs-tag .hljs-value, 41 | .hljs-phpdoc, 42 | .hljs-dartdoc, 43 | .tex .hljs-formula { 44 | color: #ed225d; 45 | } 46 | 47 | .hljs-title, 48 | .hljs-id, 49 | .scss .hljs-preprocessor { 50 | color: #900; 51 | font-weight: bold; 52 | } 53 | 54 | .hljs-list .hljs-keyword, 55 | .hljs-subst { 56 | font-weight: normal; 57 | } 58 | 59 | .hljs-class .hljs-title, 60 | .hljs-type, 61 | .vhdl .hljs-literal, 62 | .tex .hljs-command { 63 | color: #458; 64 | font-weight: bold; 65 | } 66 | 67 | .hljs-tag, 68 | .hljs-tag .hljs-title, 69 | .hljs-rules .hljs-property, 70 | .django .hljs-tag .hljs-keyword { 71 | color: #000080; 72 | font-weight: normal; 73 | } 74 | 75 | .hljs-attribute, 76 | .hljs-variable, 77 | .lisp .hljs-body { 78 | color: #008080; 79 | } 80 | 81 | .hljs-regexp { 82 | color: #009926; 83 | } 84 | 85 | .hljs-symbol, 86 | .ruby .hljs-symbol .hljs-string, 87 | .lisp .hljs-keyword, 88 | .clojure .hljs-keyword, 89 | .scheme .hljs-keyword, 90 | .tex .hljs-special, 91 | .hljs-prompt { 92 | color: #990073; 93 | } 94 | 95 | .hljs-built_in { 96 | color: #0086b3; 97 | } 98 | 99 | .hljs-preprocessor, 100 | .hljs-pragma, 101 | .hljs-pi, 102 | .hljs-doctype, 103 | .hljs-shebang, 104 | .hljs-cdata { 105 | color: #999; 106 | font-weight: bold; 107 | } 108 | 109 | .hljs-deletion { 110 | background: #fdd; 111 | } 112 | 113 | .hljs-addition { 114 | background: #dfd; 115 | } 116 | 117 | .diff .hljs-change { 118 | background: #0086b3; 119 | } 120 | 121 | .hljs-chunk { 122 | color: #aaa; 123 | } 124 | -------------------------------------------------------------------------------- /docs/assets/site.js: -------------------------------------------------------------------------------- 1 | /* global anchors */ 2 | 3 | // add anchor links to headers 4 | anchors.options.placement = 'left'; 5 | anchors.add('h3'); 6 | 7 | // Filter UI 8 | var tocElements = document.getElementById('toc').getElementsByTagName('li'); 9 | 10 | document.getElementById('filter-input').addEventListener('keyup', function(e) { 11 | var i, element, children; 12 | 13 | // enter key 14 | if (e.keyCode === 13) { 15 | // go to the first displayed item in the toc 16 | for (i = 0; i < tocElements.length; i++) { 17 | element = tocElements[i]; 18 | if (!element.classList.contains('display-none')) { 19 | location.replace(element.firstChild.href); 20 | return e.preventDefault(); 21 | } 22 | } 23 | } 24 | 25 | var match = function() { 26 | return true; 27 | }; 28 | 29 | var value = this.value.toLowerCase(); 30 | 31 | if (!value.match(/^\s*$/)) { 32 | match = function(element) { 33 | var html = element.firstChild.innerHTML; 34 | return html && html.toLowerCase().indexOf(value) !== -1; 35 | }; 36 | } 37 | 38 | for (i = 0; i < tocElements.length; i++) { 39 | element = tocElements[i]; 40 | children = Array.from(element.getElementsByTagName('li')); 41 | if (match(element) || children.some(match)) { 42 | element.classList.remove('display-none'); 43 | } else { 44 | element.classList.add('display-none'); 45 | } 46 | } 47 | }); 48 | 49 | var items = document.getElementsByClassName('toggle-sibling'); 50 | for (var j = 0; j < items.length; j++) { 51 | items[j].addEventListener('click', toggleSibling); 52 | } 53 | 54 | function toggleSibling() { 55 | var stepSibling = this.parentNode.getElementsByClassName('toggle-target')[0]; 56 | var icon = this.getElementsByClassName('icon')[0]; 57 | var klass = 'display-none'; 58 | if (stepSibling.classList.contains(klass)) { 59 | stepSibling.classList.remove(klass); 60 | icon.innerHTML = '▾'; 61 | } else { 62 | stepSibling.classList.add(klass); 63 | icon.innerHTML = '▸'; 64 | } 65 | } 66 | 67 | function showHashTarget(targetId) { 68 | if (targetId) { 69 | var hashTarget = document.getElementById(targetId); 70 | // new target is hidden 71 | if ( 72 | hashTarget && 73 | hashTarget.offsetHeight === 0 && 74 | hashTarget.parentNode.parentNode.classList.contains('display-none') 75 | ) { 76 | hashTarget.parentNode.parentNode.classList.remove('display-none'); 77 | } 78 | } 79 | } 80 | 81 | function scrollIntoView(targetId) { 82 | // Only scroll to element if we don't have a stored scroll position. 83 | if (targetId && !history.state) { 84 | var hashTarget = document.getElementById(targetId); 85 | if (hashTarget) { 86 | hashTarget.scrollIntoView(); 87 | } 88 | } 89 | } 90 | 91 | function gotoCurrentTarget() { 92 | showHashTarget(location.hash.substring(1)); 93 | scrollIntoView(location.hash.substring(1)); 94 | } 95 | 96 | window.addEventListener('hashchange', gotoCurrentTarget); 97 | gotoCurrentTarget(); 98 | 99 | var toclinks = document.getElementsByClassName('pre-open'); 100 | for (var k = 0; k < toclinks.length; k++) { 101 | toclinks[k].addEventListener('mousedown', preOpen, false); 102 | } 103 | 104 | function preOpen() { 105 | showHashTarget(this.hash.substring(1)); 106 | } 107 | 108 | var split_left = document.querySelector('#split-left'); 109 | var split_right = document.querySelector('#split-right'); 110 | var split_parent = split_left.parentNode; 111 | var cw_with_sb = split_left.clientWidth; 112 | split_left.style.overflow = 'hidden'; 113 | var cw_without_sb = split_left.clientWidth; 114 | split_left.style.overflow = ''; 115 | 116 | Split(['#split-left', '#split-right'], { 117 | elementStyle: function(dimension, size, gutterSize) { 118 | return { 119 | 'flex-basis': 'calc(' + size + '% - ' + gutterSize + 'px)' 120 | }; 121 | }, 122 | gutterStyle: function(dimension, gutterSize) { 123 | return { 124 | 'flex-basis': gutterSize + 'px' 125 | }; 126 | }, 127 | gutterSize: 20, 128 | sizes: [33, 67] 129 | }); 130 | 131 | // Chrome doesn't remember scroll position properly so do it ourselves. 132 | // Also works on Firefox and Edge. 133 | 134 | function updateState() { 135 | history.replaceState( 136 | { 137 | left_top: split_left.scrollTop, 138 | right_top: split_right.scrollTop 139 | }, 140 | document.title 141 | ); 142 | } 143 | 144 | function loadState(ev) { 145 | if (ev) { 146 | // Edge doesn't replace change history.state on popstate. 147 | history.replaceState(ev.state, document.title); 148 | } 149 | if (history.state) { 150 | split_left.scrollTop = history.state.left_top; 151 | split_right.scrollTop = history.state.right_top; 152 | } 153 | } 154 | 155 | window.addEventListener('load', function() { 156 | // Restore after Firefox scrolls to hash. 157 | setTimeout(function() { 158 | loadState(); 159 | // Update with initial scroll position. 160 | updateState(); 161 | // Update scroll positions only after we've loaded because Firefox 162 | // emits an initial scroll event with 0. 163 | split_left.addEventListener('scroll', updateState); 164 | split_right.addEventListener('scroll', updateState); 165 | }, 1); 166 | }); 167 | 168 | window.addEventListener('popstate', loadState); 169 | -------------------------------------------------------------------------------- /docs/assets/split.css: -------------------------------------------------------------------------------- 1 | .gutter { 2 | background-color: #f5f5f5; 3 | background-repeat: no-repeat; 4 | background-position: 50%; 5 | } 6 | 7 | .gutter.gutter-vertical { 8 | background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAFAQMAAABo7865AAAABlBMVEVHcEzMzMzyAv2sAAAAAXRSTlMAQObYZgAAABBJREFUeF5jOAMEEAIEEFwAn3kMwcB6I2AAAAAASUVORK5CYII='); 9 | cursor: ns-resize; 10 | } 11 | 12 | .gutter.gutter-horizontal { 13 | background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAeCAYAAADkftS9AAAAIklEQVQoU2M4c+bMfxAGAgYYmwGrIIiDjrELjpo5aiZeMwF+yNnOs5KSvgAAAABJRU5ErkJggg=='); 14 | cursor: ew-resize; 15 | } 16 | -------------------------------------------------------------------------------- /docs/assets/style.css: -------------------------------------------------------------------------------- 1 | .documentation { 2 | font-family: Helvetica, sans-serif; 3 | color: #666; 4 | line-height: 1.5; 5 | background: #f5f5f5; 6 | } 7 | 8 | .black { 9 | color: #666; 10 | } 11 | 12 | .bg-white { 13 | background-color: #fff; 14 | } 15 | 16 | h4 { 17 | margin: 20px 0 10px 0; 18 | } 19 | 20 | .documentation h3 { 21 | color: #000; 22 | } 23 | 24 | .border-bottom { 25 | border-color: #ddd; 26 | } 27 | 28 | a { 29 | color: #1184CE; 30 | text-decoration: none; 31 | } 32 | 33 | .documentation a[href]:hover { 34 | text-decoration: underline; 35 | } 36 | 37 | a:hover { 38 | cursor: pointer; 39 | } 40 | 41 | .py1-ul li { 42 | padding: 5px 0; 43 | } 44 | 45 | .max-height-100 { 46 | max-height: 100%; 47 | } 48 | 49 | .height-viewport-100 { 50 | height: 100vh; 51 | } 52 | 53 | section:target h3 { 54 | font-weight:700; 55 | } 56 | 57 | .documentation td, 58 | .documentation th { 59 | padding: .25rem .25rem; 60 | } 61 | 62 | h1:hover .anchorjs-link, 63 | h2:hover .anchorjs-link, 64 | h3:hover .anchorjs-link, 65 | h4:hover .anchorjs-link { 66 | opacity: 1; 67 | } 68 | 69 | .fix-3 { 70 | width: 25%; 71 | max-width: 244px; 72 | } 73 | 74 | .fix-3 { 75 | width: 25%; 76 | max-width: 244px; 77 | } 78 | 79 | @media (min-width: 52em) { 80 | .fix-margin-3 { 81 | margin-left: 25%; 82 | } 83 | } 84 | 85 | .pre, pre, code, .code { 86 | font-family: Source Code Pro,Menlo,Consolas,Liberation Mono,monospace; 87 | font-size: 14px; 88 | } 89 | 90 | .fill-light { 91 | background: #F9F9F9; 92 | } 93 | 94 | .width2 { 95 | width: 1rem; 96 | } 97 | 98 | .input { 99 | font-family: inherit; 100 | display: block; 101 | width: 100%; 102 | height: 2rem; 103 | padding: .5rem; 104 | margin-bottom: 1rem; 105 | border: 1px solid #ccc; 106 | font-size: .875rem; 107 | border-radius: 3px; 108 | box-sizing: border-box; 109 | } 110 | 111 | table { 112 | border-collapse: collapse; 113 | } 114 | 115 | .prose table th, 116 | .prose table td { 117 | text-align: left; 118 | padding:8px; 119 | border:1px solid #ddd; 120 | } 121 | 122 | .prose table th:nth-child(1) { border-right: none; } 123 | .prose table th:nth-child(2) { border-left: none; } 124 | 125 | .prose table { 126 | border:1px solid #ddd; 127 | } 128 | 129 | .prose-big { 130 | font-size: 18px; 131 | line-height: 30px; 132 | } 133 | 134 | .quiet { 135 | opacity: 0.7; 136 | } 137 | 138 | .minishadow { 139 | box-shadow: 2px 2px 10px #f3f3f3; 140 | } 141 | -------------------------------------------------------------------------------- /docs/badge.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | document 13 | document 14 | 0% 15 | 0% 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/coverage.json: -------------------------------------------------------------------------------- 1 | { 2 | "coverage": "0%", 3 | "expectCount": 7, 4 | "actualCount": 0, 5 | "files": { 6 | "lib/getPublicComments.js": { 7 | "expectCount": 6, 8 | "actualCount": 0, 9 | "undocumentLines": [ 10 | 1, 11 | 2, 12 | 3, 13 | 4, 14 | 15, 15 | 21 16 | ] 17 | }, 18 | "lib/utils/getBinarySize.js": { 19 | "expectCount": 1, 20 | "actualCount": 0, 21 | "undocumentLines": [ 22 | 1 23 | ] 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /docs/css/github.css: -------------------------------------------------------------------------------- 1 | /* github markdown */ 2 | .github-markdown { 3 | font-size: 16px; 4 | } 5 | 6 | .github-markdown h1, 7 | .github-markdown h2, 8 | .github-markdown h3, 9 | .github-markdown h4, 10 | .github-markdown h5 { 11 | margin-top: 1em; 12 | margin-bottom: 16px; 13 | font-weight: bold; 14 | padding: 0; 15 | } 16 | 17 | .github-markdown h1:nth-of-type(1) { 18 | margin-top: 0; 19 | } 20 | 21 | .github-markdown h1 { 22 | font-size: 2em; 23 | padding-bottom: 0.3em; 24 | } 25 | 26 | .github-markdown h2 { 27 | font-size: 1.75em; 28 | padding-bottom: 0.3em; 29 | } 30 | 31 | .github-markdown h3 { 32 | font-size: 1.5em; 33 | } 34 | 35 | .github-markdown h4 { 36 | font-size: 1.25em; 37 | } 38 | 39 | .github-markdown h5 { 40 | font-size: 1em; 41 | } 42 | 43 | .github-markdown ul, .github-markdown ol { 44 | padding-left: 2em; 45 | } 46 | 47 | .github-markdown pre > code { 48 | font-size: 0.85em; 49 | } 50 | 51 | .github-markdown table { 52 | margin-bottom: 1em; 53 | border-collapse: collapse; 54 | border-spacing: 0; 55 | } 56 | 57 | .github-markdown table tr { 58 | background-color: #fff; 59 | border-top: 1px solid #ccc; 60 | } 61 | 62 | .github-markdown table th, 63 | .github-markdown table td { 64 | padding: 6px 13px; 65 | border: 1px solid #ddd; 66 | } 67 | 68 | .github-markdown table tr:nth-child(2n) { 69 | background-color: #f8f8f8; 70 | } 71 | 72 | .github-markdown hr { 73 | border-right: 0; 74 | border-bottom: 1px solid #e5e5e5; 75 | border-left: 0; 76 | border-top: 0; 77 | } 78 | 79 | /** badge(.svg) does not have border */ 80 | .github-markdown img:not([src*=".svg"]) { 81 | max-width: 100%; 82 | box-shadow: 1px 1px 1px rgba(0,0,0,0.5); 83 | } 84 | -------------------------------------------------------------------------------- /docs/css/identifiers.css: -------------------------------------------------------------------------------- 1 | .identifiers-wrap { 2 | display: flex; 3 | align-items: flex-start; 4 | } 5 | 6 | .identifier-dir-tree { 7 | background: #fff; 8 | border: solid 1px #ddd; 9 | border-radius: 0.25em; 10 | top: 52px; 11 | position: -webkit-sticky; 12 | position: sticky; 13 | max-height: calc(100vh - 155px); 14 | overflow-y: scroll; 15 | min-width: 200px; 16 | margin-left: 1em; 17 | } 18 | 19 | .identifier-dir-tree-header { 20 | padding: 0.5em; 21 | background-color: #fafafa; 22 | border-bottom: solid 1px #ddd; 23 | } 24 | 25 | .identifier-dir-tree-content { 26 | padding: 0 0.5em 0; 27 | } 28 | 29 | .identifier-dir-tree-content > div { 30 | padding-top: 0.25em; 31 | padding-bottom: 0.25em; 32 | } 33 | 34 | .identifier-dir-tree-content a { 35 | color: inherit; 36 | } 37 | 38 | -------------------------------------------------------------------------------- /docs/css/manual.css: -------------------------------------------------------------------------------- 1 | .github-markdown .manual-toc { 2 | padding-left: 0; 3 | } 4 | 5 | .manual-index .manual-cards { 6 | display: flex; 7 | flex-wrap: wrap; 8 | } 9 | 10 | .manual-index .manual-card-wrap { 11 | width: 280px; 12 | padding: 10px 20px 10px 0; 13 | box-sizing: border-box; 14 | } 15 | 16 | .manual-index .manual-card-wrap > h1 { 17 | margin: 0; 18 | font-size: 1em; 19 | font-weight: 600; 20 | padding: 0.2em 0 0.2em 0.5em; 21 | border-radius: 0.1em 0.1em 0 0; 22 | border: none; 23 | } 24 | 25 | .manual-index .manual-card-wrap > h1 span { 26 | color: #555; 27 | } 28 | 29 | .manual-index .manual-card { 30 | height: 200px; 31 | overflow: hidden; 32 | border: solid 1px rgba(230, 230, 230, 0.84); 33 | border-radius: 0 0 0.1em 0.1em; 34 | padding: 8px; 35 | position: relative; 36 | } 37 | 38 | .manual-index .manual-card > div { 39 | transform: scale(0.4); 40 | transform-origin: 0 0; 41 | width: 250%; 42 | } 43 | 44 | .manual-index .manual-card > a { 45 | position: absolute; 46 | top: 0; 47 | left: 0; 48 | width: 100%; 49 | height: 100%; 50 | background: rgba(210, 210, 210, 0.1); 51 | } 52 | 53 | .manual-index .manual-card > a:hover { 54 | background: none; 55 | } 56 | 57 | .manual-index .manual-badge { 58 | margin: 0; 59 | } 60 | 61 | .manual-index .manual-user-index { 62 | margin-bottom: 1em; 63 | border-bottom: solid 1px #ddd; 64 | } 65 | 66 | .manual-root .navigation { 67 | padding-left: 4px; 68 | margin-top: 4px; 69 | } 70 | 71 | .navigation .manual-toc-root > div { 72 | padding-left: 0.25em; 73 | padding-right: 0.75em; 74 | } 75 | 76 | .github-markdown .manual-toc-title a { 77 | color: inherit; 78 | } 79 | 80 | .manual-breadcrumb-list { 81 | font-size: 0.8em; 82 | margin-bottom: 1em; 83 | } 84 | 85 | .manual-toc-title a:hover { 86 | color: #039BE5; 87 | } 88 | 89 | .manual-toc li { 90 | margin: 0.75em 0; 91 | list-style-type: none; 92 | } 93 | 94 | .navigation .manual-toc [class^="indent-h"] a { 95 | color: #666; 96 | } 97 | 98 | .navigation .manual-toc .indent-h1 a { 99 | color: #555; 100 | font-weight: 600; 101 | display: block; 102 | } 103 | 104 | .manual-toc .indent-h1 { 105 | display: block; 106 | margin: 0.4em 0 0 0.25em; 107 | padding: 0.2em 0 0.2em 0.5em; 108 | border-radius: 0.1em; 109 | } 110 | 111 | .manual-root .navigation .manual-toc li:not(.indent-h1) { 112 | margin-top: 0.5em; 113 | } 114 | 115 | .manual-toc .indent-h2 { 116 | display: none; 117 | margin-left: 1.5em; 118 | } 119 | .manual-toc .indent-h3 { 120 | display: none; 121 | margin-left: 2.5em; 122 | } 123 | .manual-toc .indent-h4 { 124 | display: none; 125 | margin-left: 3.5em; 126 | } 127 | .manual-toc .indent-h5 { 128 | display: none; 129 | margin-left: 4.5em; 130 | } 131 | 132 | .manual-nav li { 133 | margin: 0.75em 0; 134 | } 135 | -------------------------------------------------------------------------------- /docs/css/prettify-tomorrow.css: -------------------------------------------------------------------------------- 1 | /* Tomorrow Theme */ 2 | /* Original theme - https://github.com/chriskempson/tomorrow-theme */ 3 | /* Pretty printing styles. Used with prettify.js. */ 4 | /* SPAN elements with the classes below are added by prettyprint. */ 5 | /* plain text */ 6 | .pln { 7 | color: #4d4d4c; } 8 | 9 | @media screen { 10 | /* string content */ 11 | .str { 12 | color: #718c00; } 13 | 14 | /* a keyword */ 15 | .kwd { 16 | color: #8959a8; } 17 | 18 | /* a comment */ 19 | .com { 20 | color: #8e908c; } 21 | 22 | /* a type name */ 23 | .typ { 24 | color: #4271ae; } 25 | 26 | /* a literal value */ 27 | .lit { 28 | color: #f5871f; } 29 | 30 | /* punctuation */ 31 | .pun { 32 | color: #4d4d4c; } 33 | 34 | /* lisp open bracket */ 35 | .opn { 36 | color: #4d4d4c; } 37 | 38 | /* lisp close bracket */ 39 | .clo { 40 | color: #4d4d4c; } 41 | 42 | /* a markup tag name */ 43 | .tag { 44 | color: #c82829; } 45 | 46 | /* a markup attribute name */ 47 | .atn { 48 | color: #f5871f; } 49 | 50 | /* a markup attribute value */ 51 | .atv { 52 | color: #3e999f; } 53 | 54 | /* a declaration */ 55 | .dec { 56 | color: #f5871f; } 57 | 58 | /* a variable name */ 59 | .var { 60 | color: #c82829; } 61 | 62 | /* a function name */ 63 | .fun { 64 | color: #4271ae; } } 65 | /* Use higher contrast and text-weight for printable form. */ 66 | @media print, projection { 67 | .str { 68 | color: #060; } 69 | 70 | .kwd { 71 | color: #006; 72 | font-weight: bold; } 73 | 74 | .com { 75 | color: #600; 76 | font-style: italic; } 77 | 78 | .typ { 79 | color: #404; 80 | font-weight: bold; } 81 | 82 | .lit { 83 | color: #044; } 84 | 85 | .pun, .opn, .clo { 86 | color: #440; } 87 | 88 | .tag { 89 | color: #006; 90 | font-weight: bold; } 91 | 92 | .atn { 93 | color: #404; } 94 | 95 | .atv { 96 | color: #060; } } 97 | /* Style */ 98 | /* 99 | pre.prettyprint { 100 | background: white; 101 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 102 | font-size: 12px; 103 | line-height: 1.5; 104 | border: 1px solid #ccc; 105 | padding: 10px; } 106 | */ 107 | 108 | /* Specify class=linenums on a pre to get line numbering */ 109 | ol.linenums { 110 | margin-top: 0; 111 | margin-bottom: 0; } 112 | 113 | /* IE indents via margin-left */ 114 | li.L0, 115 | li.L1, 116 | li.L2, 117 | li.L3, 118 | li.L4, 119 | li.L5, 120 | li.L6, 121 | li.L7, 122 | li.L8, 123 | li.L9 { 124 | /* */ } 125 | 126 | /* Alternate shading for lines */ 127 | li.L1, 128 | li.L3, 129 | li.L5, 130 | li.L7, 131 | li.L9 { 132 | /* */ } 133 | -------------------------------------------------------------------------------- /docs/css/search.css: -------------------------------------------------------------------------------- 1 | /* search box */ 2 | .search-box { 3 | position: absolute; 4 | top: 10px; 5 | right: 50px; 6 | padding-right: 8px; 7 | padding-bottom: 10px; 8 | line-height: normal; 9 | font-size: 12px; 10 | } 11 | 12 | .search-box img { 13 | width: 20px; 14 | vertical-align: top; 15 | } 16 | 17 | .search-input { 18 | display: inline; 19 | visibility: hidden; 20 | width: 0; 21 | padding: 2px; 22 | height: 1.5em; 23 | outline: none; 24 | background: transparent; 25 | border: 1px #0af; 26 | border-style: none none solid none; 27 | vertical-align: bottom; 28 | } 29 | 30 | .search-input-edge { 31 | display: none; 32 | width: 1px; 33 | height: 5px; 34 | background-color: #0af; 35 | vertical-align: bottom; 36 | } 37 | 38 | .search-result { 39 | position: absolute; 40 | display: none; 41 | height: 600px; 42 | width: 100%; 43 | padding: 0; 44 | margin-top: 5px; 45 | margin-left: 24px; 46 | background: white; 47 | box-shadow: 1px 1px 4px rgb(0,0,0); 48 | white-space: nowrap; 49 | overflow-y: scroll; 50 | } 51 | 52 | .search-result-import-path { 53 | color: #aaa; 54 | font-size: 12px; 55 | } 56 | 57 | .search-result li { 58 | list-style: none; 59 | padding: 2px 4px; 60 | } 61 | 62 | .search-result li a { 63 | display: block; 64 | } 65 | 66 | .search-result li.selected { 67 | background: #ddd; 68 | } 69 | 70 | .search-result li.search-separator { 71 | background: rgb(37, 138, 175); 72 | color: white; 73 | } 74 | 75 | .search-box.active .search-input { 76 | visibility: visible; 77 | transition: width 0.2s ease-out; 78 | width: 300px; 79 | } 80 | 81 | .search-box.active .search-input-edge { 82 | display: inline-block; 83 | } 84 | 85 | -------------------------------------------------------------------------------- /docs/css/source.css: -------------------------------------------------------------------------------- 1 | table.files-summary { 2 | width: 100%; 3 | margin: 10px 0; 4 | border-spacing: 0; 5 | border: 0; 6 | border-collapse: collapse; 7 | text-align: right; 8 | } 9 | 10 | table.files-summary tbody tr:hover { 11 | background: #eee; 12 | } 13 | 14 | table.files-summary td:first-child, 15 | table.files-summary td:nth-of-type(2) { 16 | text-align: left; 17 | } 18 | 19 | table.files-summary[data-use-coverage="false"] td.coverage { 20 | display: none; 21 | } 22 | 23 | table.files-summary thead { 24 | background: #fafafa; 25 | } 26 | 27 | table.files-summary td { 28 | border: solid 1px #ddd; 29 | padding: 4px 10px; 30 | vertical-align: top; 31 | } 32 | 33 | table.files-summary td.identifiers > span { 34 | display: block; 35 | margin-top: 4px; 36 | } 37 | table.files-summary td.identifiers > span:first-child { 38 | margin-top: 0; 39 | } 40 | 41 | table.files-summary .coverage-count { 42 | font-size: 12px; 43 | color: #aaa; 44 | display: inline-block; 45 | min-width: 40px; 46 | } 47 | 48 | .total-coverage-count { 49 | position: relative; 50 | bottom: 2px; 51 | font-size: 12px; 52 | color: #666; 53 | font-weight: 500; 54 | padding-left: 5px; 55 | } 56 | -------------------------------------------------------------------------------- /docs/css/style.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Roboto:400,300,700); 2 | @import url(https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400italic,600,700); 3 | @import url(./manual.css); 4 | @import url(./source.css); 5 | @import url(./test.css); 6 | @import url(./identifiers.css); 7 | @import url(./github.css); 8 | @import url(./search.css); 9 | 10 | * { 11 | margin: 0; 12 | padding: 0; 13 | text-decoration: none; 14 | } 15 | 16 | html 17 | { 18 | font-family: 'Source Sans Pro', 'Roboto', sans-serif; 19 | overflow: auto; 20 | /*font-size: 14px;*/ 21 | /*color: #4d4e53;*/ 22 | /*color: rgba(0, 0, 0, .68);*/ 23 | color: #555; 24 | background-color: #fff; 25 | } 26 | 27 | a { 28 | /*color: #0095dd;*/ 29 | /*color:rgb(37, 138, 175);*/ 30 | color: #039BE5; 31 | } 32 | 33 | code a:hover { 34 | text-decoration: underline; 35 | } 36 | 37 | ul, ol { 38 | padding-left: 20px; 39 | } 40 | 41 | ul li { 42 | list-style: disc; 43 | margin: 4px 0; 44 | } 45 | 46 | ol li { 47 | margin: 4px 0; 48 | } 49 | 50 | h1 { 51 | margin-bottom: 10px; 52 | font-size: 34px; 53 | font-weight: 300; 54 | border-bottom: solid 1px #ddd; 55 | } 56 | 57 | h2 { 58 | margin-top: 24px; 59 | margin-bottom: 10px; 60 | font-size: 20px; 61 | border-bottom: solid 1px #ddd; 62 | font-weight: 300; 63 | } 64 | 65 | h3 { 66 | position: relative; 67 | font-size: 16px; 68 | margin-bottom: 12px; 69 | padding: 4px; 70 | font-weight: 300; 71 | } 72 | 73 | details { 74 | cursor: pointer; 75 | } 76 | 77 | del { 78 | text-decoration: line-through; 79 | } 80 | 81 | p { 82 | margin-bottom: 15px; 83 | line-height: 1.5; 84 | } 85 | 86 | code { 87 | font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; 88 | } 89 | 90 | pre > code { 91 | display: block; 92 | } 93 | 94 | pre.prettyprint, pre > code { 95 | padding: 4px; 96 | margin: 1em 0; 97 | background-color: #f5f5f5; 98 | border-radius: 3px; 99 | } 100 | 101 | pre.prettyprint > code { 102 | margin: 0; 103 | } 104 | 105 | p > code, 106 | li > code { 107 | padding: 0.2em 0.5em; 108 | margin: 0; 109 | font-size: 85%; 110 | background-color: rgba(0,0,0,0.04); 111 | border-radius: 3px; 112 | } 113 | 114 | .code { 115 | font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; 116 | font-size: 13px; 117 | } 118 | 119 | .import-path pre.prettyprint, 120 | .import-path pre.prettyprint code { 121 | margin: 0; 122 | padding: 0; 123 | border: none; 124 | background: white; 125 | } 126 | 127 | .layout-container { 128 | /*display: flex;*/ 129 | /*flex-direction: row;*/ 130 | /*justify-content: flex-start;*/ 131 | /*align-items: stretch;*/ 132 | } 133 | 134 | .layout-container > header { 135 | display: flex; 136 | height: 40px; 137 | line-height: 40px; 138 | font-size: 16px; 139 | padding: 0 10px; 140 | margin: 0; 141 | position: fixed; 142 | width: 100%; 143 | z-index: 1; 144 | background-color: #fafafa; 145 | top: 0; 146 | border-bottom: solid 1px #ddd; 147 | } 148 | .layout-container > header > a{ 149 | margin: 0 5px; 150 | color: #444; 151 | } 152 | 153 | .layout-container > header > a.repo-url-github { 154 | font-size: 0; 155 | display: inline-block; 156 | width: 20px; 157 | height: 38px; 158 | background: url("../image/github.png") no-repeat center; 159 | background-size: 20px; 160 | vertical-align: top; 161 | } 162 | 163 | .navigation { 164 | position: fixed; 165 | top: 0; 166 | left: 0; 167 | box-sizing: border-box; 168 | width: 250px; 169 | height: 100%; 170 | padding-top: 40px; 171 | padding-left: 15px; 172 | padding-bottom: 2em; 173 | margin-top:1em; 174 | overflow-x: scroll; 175 | box-shadow: rgba(255, 255, 255, 1) -1px 0 0 inset; 176 | border-right: 1px solid #ddd; 177 | } 178 | 179 | .navigation ul { 180 | padding: 0; 181 | } 182 | 183 | .navigation li { 184 | list-style: none; 185 | margin: 4px 0; 186 | white-space: nowrap; 187 | } 188 | 189 | .navigation li a { 190 | color: #666; 191 | } 192 | 193 | .navigation .nav-dir-path { 194 | display: block; 195 | margin-top: 0.7em; 196 | margin-bottom: 0.25em; 197 | font-weight: 600; 198 | } 199 | 200 | .kind-class, 201 | .kind-interface, 202 | .kind-function, 203 | .kind-typedef, 204 | .kind-variable, 205 | .kind-external { 206 | margin-left: 0.75em; 207 | width: 1.2em; 208 | height: 1.2em; 209 | display: inline-block; 210 | text-align: center; 211 | border-radius: 0.2em; 212 | margin-right: 0.2em; 213 | font-weight: bold; 214 | line-height: 1.2em; 215 | } 216 | 217 | .kind-class { 218 | color: #009800; 219 | background-color: #bfe5bf; 220 | } 221 | 222 | .kind-interface { 223 | color: #fbca04; 224 | background-color: #fef2c0; 225 | } 226 | 227 | .kind-function { 228 | color: #6b0090; 229 | background-color: #d6bdde; 230 | } 231 | 232 | .kind-variable { 233 | color: #eb6420; 234 | background-color: #fad8c7; 235 | } 236 | 237 | .kind-typedef { 238 | color: #db001e; 239 | background-color: #edbec3; 240 | } 241 | 242 | .kind-external { 243 | color: #0738c3; 244 | background-color: #bbcbea; 245 | } 246 | 247 | .summary span[class^="kind-"] { 248 | margin-left: 0; 249 | } 250 | 251 | h1 .version, 252 | h1 .url a { 253 | font-size: 14px; 254 | color: #aaa; 255 | } 256 | 257 | .content { 258 | margin-top: 40px; 259 | margin-left: 250px; 260 | padding: 10px 50px 10px 20px; 261 | } 262 | 263 | .header-notice { 264 | font-size: 14px; 265 | color: #aaa; 266 | margin: 0; 267 | } 268 | 269 | .expression-extends .prettyprint { 270 | margin-left: 10px; 271 | background: white; 272 | } 273 | 274 | .extends-chain { 275 | border-bottom: 1px solid#ddd; 276 | padding-bottom: 10px; 277 | margin-bottom: 10px; 278 | } 279 | 280 | .extends-chain span:nth-of-type(1) { 281 | padding-left: 10px; 282 | } 283 | 284 | .extends-chain > div { 285 | margin: 5px 0; 286 | } 287 | 288 | .description table { 289 | font-size: 14px; 290 | border-spacing: 0; 291 | border: 0; 292 | border-collapse: collapse; 293 | } 294 | 295 | .description thead { 296 | background: #999; 297 | color: white; 298 | } 299 | 300 | .description table td, 301 | .description table th { 302 | border: solid 1px #ddd; 303 | padding: 4px; 304 | font-weight: normal; 305 | } 306 | 307 | .flat-list ul { 308 | padding-left: 0; 309 | } 310 | 311 | .flat-list li { 312 | display: inline; 313 | list-style: none; 314 | } 315 | 316 | table.summary { 317 | width: 100%; 318 | margin: 10px 0; 319 | border-spacing: 0; 320 | border: 0; 321 | border-collapse: collapse; 322 | } 323 | 324 | table.summary thead { 325 | background: #fafafa; 326 | } 327 | 328 | table.summary td { 329 | border: solid 1px #ddd; 330 | padding: 4px 10px; 331 | } 332 | 333 | table.summary tbody td:nth-child(1) { 334 | text-align: right; 335 | white-space: nowrap; 336 | min-width: 64px; 337 | vertical-align: top; 338 | } 339 | 340 | table.summary tbody td:nth-child(2) { 341 | width: 100%; 342 | border-right: none; 343 | } 344 | 345 | table.summary tbody td:nth-child(3) { 346 | white-space: nowrap; 347 | border-left: none; 348 | vertical-align: top; 349 | } 350 | 351 | table.summary td > div:nth-of-type(2) { 352 | padding-top: 4px; 353 | padding-left: 15px; 354 | } 355 | 356 | table.summary td p { 357 | margin-bottom: 0; 358 | } 359 | 360 | .inherited-summary thead td { 361 | padding-left: 2px; 362 | } 363 | 364 | .inherited-summary thead a { 365 | color: white; 366 | } 367 | 368 | .inherited-summary .summary tbody { 369 | display: none; 370 | } 371 | 372 | .inherited-summary .summary .toggle { 373 | padding: 0 4px; 374 | font-size: 12px; 375 | cursor: pointer; 376 | } 377 | .inherited-summary .summary .toggle.closed:before { 378 | content: "▶"; 379 | } 380 | .inherited-summary .summary .toggle.opened:before { 381 | content: "▼"; 382 | } 383 | 384 | .member, .method { 385 | margin-bottom: 24px; 386 | } 387 | 388 | table.params { 389 | width: 100%; 390 | margin: 10px 0; 391 | border-spacing: 0; 392 | border: 0; 393 | border-collapse: collapse; 394 | } 395 | 396 | table.params thead { 397 | background: #eee; 398 | color: #aaa; 399 | } 400 | 401 | table.params td { 402 | padding: 4px; 403 | border: solid 1px #ddd; 404 | } 405 | 406 | table.params td p { 407 | margin: 0; 408 | } 409 | 410 | .content .detail > * { 411 | margin: 15px 0; 412 | } 413 | 414 | .content .detail > h3 { 415 | color: black; 416 | background-color: #f0f0f0; 417 | } 418 | 419 | .content .detail > div { 420 | margin-left: 10px; 421 | } 422 | 423 | .content .detail > .import-path { 424 | margin-top: -8px; 425 | } 426 | 427 | .content .detail + .detail { 428 | margin-top: 30px; 429 | } 430 | 431 | .content .detail .throw td:first-child { 432 | padding-right: 10px; 433 | } 434 | 435 | .content .detail h4 + :not(pre) { 436 | padding-left: 0; 437 | margin-left: 10px; 438 | } 439 | 440 | .content .detail h4 + ul li { 441 | list-style: none; 442 | } 443 | 444 | .return-param * { 445 | display: inline; 446 | } 447 | 448 | .argument-params { 449 | margin-bottom: 20px; 450 | } 451 | 452 | .return-type { 453 | padding-right: 10px; 454 | font-weight: normal; 455 | } 456 | 457 | .return-desc { 458 | margin-left: 10px; 459 | margin-top: 4px; 460 | } 461 | 462 | .return-desc p { 463 | margin: 0; 464 | } 465 | 466 | .deprecated, .experimental, .instance-docs { 467 | border-left: solid 5px orange; 468 | padding-left: 4px; 469 | margin: 4px 0; 470 | } 471 | 472 | tr.listen p, 473 | tr.throw p, 474 | tr.emit p{ 475 | margin-bottom: 10px; 476 | } 477 | 478 | .version, .since { 479 | color: #aaa; 480 | } 481 | 482 | h3 .right-info { 483 | position: absolute; 484 | right: 4px; 485 | font-size: 14px; 486 | } 487 | 488 | .version + .since:before { 489 | content: '| '; 490 | } 491 | 492 | .see { 493 | margin-top: 10px; 494 | } 495 | 496 | .see h4 { 497 | margin: 4px 0; 498 | } 499 | 500 | .content .detail h4 + .example-doc { 501 | margin: 6px 0; 502 | } 503 | 504 | .example-caption { 505 | position: relative; 506 | bottom: -1px; 507 | display: inline-block; 508 | padding: 4px; 509 | font-style: italic; 510 | background-color: #f5f5f5; 511 | font-weight: bold; 512 | border-radius: 3px; 513 | border-bottom-left-radius: 0; 514 | border-bottom-right-radius: 0; 515 | } 516 | 517 | .example-caption + pre.source-code { 518 | margin-top: 0; 519 | border-top-left-radius: 0; 520 | } 521 | 522 | footer, .file-footer { 523 | text-align: right; 524 | font-style: italic; 525 | font-weight: 100; 526 | font-size: 13px; 527 | margin-right: 50px; 528 | margin-left: 270px; 529 | border-top: 1px solid #ddd; 530 | padding-top: 30px; 531 | margin-top: 20px; 532 | padding-bottom: 10px; 533 | } 534 | 535 | footer img { 536 | width: 24px; 537 | vertical-align: middle; 538 | padding-left: 4px; 539 | position: relative; 540 | top: -3px; 541 | opacity: 0.6; 542 | } 543 | 544 | pre.source-code { 545 | padding: 4px; 546 | } 547 | 548 | pre.raw-source-code > code { 549 | padding: 0; 550 | margin: 0; 551 | font-size: 12px; 552 | background: #fff; 553 | border: solid 1px #ddd; 554 | line-height: 1.5; 555 | } 556 | 557 | pre.raw-source-code > code > ol { 558 | counter-reset:number; 559 | list-style:none; 560 | margin:0; 561 | padding:0; 562 | overflow: hidden; 563 | } 564 | 565 | pre.raw-source-code > code > ol li:before { 566 | counter-increment: number; 567 | content: counter(number); 568 | display: inline-block; 569 | min-width: 3em; 570 | color: #aaa; 571 | text-align: right; 572 | padding-right: 1em; 573 | } 574 | 575 | pre.source-code.line-number { 576 | padding: 0; 577 | } 578 | 579 | pre.source-code ol { 580 | background: #eee; 581 | padding-left: 40px; 582 | } 583 | 584 | pre.source-code li { 585 | background: white; 586 | padding-left: 4px; 587 | list-style: decimal; 588 | margin: 0; 589 | } 590 | 591 | pre.source-code.line-number li.active { 592 | background: rgb(255, 255, 150) !important; 593 | } 594 | 595 | pre.source-code.line-number li.error-line { 596 | background: #ffb8bf; 597 | } 598 | 599 | .inner-link-active { 600 | /*background: rgb(255, 255, 150) !important;*/ 601 | background: #039BE5 !important; 602 | color: #fff !important; 603 | padding-left: 0.1em !important; 604 | } 605 | 606 | .inner-link-active a { 607 | color: inherit; 608 | } 609 | -------------------------------------------------------------------------------- /docs/css/test.css: -------------------------------------------------------------------------------- 1 | table.test-summary thead { 2 | background: #fafafa; 3 | } 4 | 5 | table.test-summary thead .test-description { 6 | width: 50%; 7 | } 8 | 9 | table.test-summary { 10 | width: 100%; 11 | margin: 10px 0; 12 | border-spacing: 0; 13 | border: 0; 14 | border-collapse: collapse; 15 | } 16 | 17 | table.test-summary thead .test-count { 18 | width: 3em; 19 | } 20 | 21 | table.test-summary tbody tr:hover { 22 | background-color: #eee; 23 | } 24 | 25 | table.test-summary td { 26 | border: solid 1px #ddd; 27 | padding: 4px 10px; 28 | vertical-align: top; 29 | } 30 | 31 | table.test-summary td p { 32 | margin: 0; 33 | } 34 | 35 | table.test-summary tr.test-interface .toggle { 36 | display: inline-block; 37 | float: left; 38 | margin-right: 4px; 39 | cursor: pointer; 40 | font-size: 0.8em; 41 | padding-top: 0.25em; 42 | } 43 | 44 | table.test-summary tr.test-interface .toggle.opened:before { 45 | content: '▼'; 46 | } 47 | 48 | table.test-summary tr.test-interface .toggle.closed:before { 49 | content: '▶'; 50 | } 51 | 52 | table.test-summary .test-target > span { 53 | display: block; 54 | margin-top: 4px; 55 | } 56 | table.test-summary .test-target > span:first-child { 57 | margin-top: 0; 58 | } 59 | -------------------------------------------------------------------------------- /docs/file/lib/backgroundFinder.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | lib/backgroundFinder.js | background-finder 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | Home 16 | 17 | Reference 18 | Source 19 | 20 | 27 |
28 | 29 | 35 | 36 |

lib/backgroundFinder.js

37 |
/**
 38 |  * backgroundFinder module
 39 |  */
 40 | 
 41 | module.exports = ({ dependencies: { extractRepoDetails, getUserDiscussionIssue, getUserCommentedIssues, getCommentsOnIssue, sentimentAnalyser, createDiscussionIssue } }) => {
 42 |   /**
 43 |      * backgroundFinder
 44 |      * @param {object} context - context argument.
 45 |    */
 46 |   const backgroundFinder = async(context) => {
 47 |     if (context.isBot) return
 48 |     const owner = context.payload.repository.owner.login
 49 |     const username = context.payload.comment.user.login
 50 |     context.log(`Analyis for ${username} has started`)
 51 | 
 52 |     /* -- Check if user is already found hostile -- */
 53 |     const userIssueResult = await getUserDiscussionIssue(context, { owner, username })
 54 |     const alreadyFoundHostile = userIssueResult.data.total_count >= 1
 55 |     if (alreadyFoundHostile) {
 56 |       context.log(`${username} has already been found hostile before.\nTerminating ${username}'s analysis.`)
 57 |       return
 58 |     }
 59 |     /* ^- -^ */
 60 | 
 61 |     context.log(`${username} has not been found hostile before. \nCollection of Public Comments starting.`)
 62 |     const issuesResult = await getUserCommentedIssues(context, { username })
 63 |     const { data: { items: issues } } = issuesResult
 64 |     const userToxicComments = []
 65 |     let userToxicCommentsLimit = 3
 66 |     let totalUserComments = 0
 67 | 
 68 |     for (let issue of issues) {
 69 |       // for each issue in search result
 70 |       const issueNum = issue.number
 71 |       const repoUrl = issue.repository_url
 72 |       context.log(`Fetching comments on ${issue.url}`)
 73 |       const { data: commentsOnIssue } = await getCommentsOnIssue(context, { issueNum, ...extractRepoDetails(repoUrl) })
 74 | 
 75 |       // we'll get 30 comments on issueNum issue
 76 |       const userCommentsOnIssue = [] // stores only the username's comments
 77 |       for (let comment of commentsOnIssue) {
 78 |         if (comment.user.type !== 'Bot' && comment.user.login === username) {
 79 |           userCommentsOnIssue.push(comment)
 80 |         }
 81 |       }
 82 |       totalUserComments += userCommentsOnIssue.length
 83 | 
 84 |       let commentBlob = userCommentsOnIssue.map(comment => comment.body).join('.\n')
 85 |       if (commentBlob.length <= 0) continue // empty commentBlob
 86 | 
 87 |       const toxicScore = await sentimentAnalyser(commentBlob.substr(0, 3000)) // perspective api limits the text size to 3000B
 88 |       const isToxic = toxicScore >= 0.6
 89 |       context.log('toxicScore is', toxicScore)
 90 |       if (isToxic) {
 91 |         userToxicCommentsLimit -= 1
 92 |         userToxicComments.push({
 93 |           link: issue.html_url,
 94 |           text: commentBlob,
 95 |           toxicScore
 96 |         })
 97 |       }
 98 | 
 99 |       if (userToxicCommentsLimit <= 0) {
100 |         const { data: discussionIssueData } = await createDiscussionIssue(context, { username, owner, toxicComments: userToxicComments })
101 |         context.log(`Discussion issue for ${username} has been created. Check out ${discussionIssueData.html_url}`)
102 |         context.log(`${username}'s ${totalUserComments} comments were analysed`)
103 |         break
104 |       }
105 |     }
106 |   }
107 | 
108 |   return backgroundFinder
109 | }
110 | 
111 | 112 |
113 | 114 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /docs/file/lib/getPublicComments.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | lib/getPublicComments.js | background-finder 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | Home 16 | 17 | Reference 18 | Source 19 | 20 | 27 |
28 | 29 | 35 | 36 |

lib/getPublicComments.js

37 |
const extractRepoDetails = require('./utils/extractRepoDetailsFromUrl')
38 | const filterUserComments = require('./utils/filterUserComments')
39 | const getUserCommentedIssues = require('./github-api/getUserCommentedIssues')
40 | const getCommentsOnIssue = require('./github-api/getCommentsOnIssue')
41 | 
42 | module.exports = async(context, { username }) => {
43 |   const issuesResult = await getUserCommentedIssues(context, { username })
44 |   const { data: { total_count, items: issues } } = issuesResult
45 |   console.log('total_count', total_count)
46 |   const commentsResults = await getCommentsOnIssues(context, { issues })
47 |   const userComments = getUserComments(commentsResults, username)
48 |   return userComments
49 | }
50 | 
51 | async function getCommentsOnIssues (context, { issues }) {
52 |   const commentsPromises = issues
53 |     .map(({ number, repository_url: url }) => getCommentsOnIssue(context, { issueNum: number, ...extractRepoDetails(url) }))
54 |   return Promise.all(commentsPromises)
55 | }
56 | 
57 | function getUserComments (commentsResults, username) {
58 |   const userComments = []
59 |   commentsResults.forEach(({ data: commentsData }) => {
60 |     const userCommentsOnIssue = filterUserComments(commentsData, username)
61 |     // userCommentsOnIssue is an array holding the wanted user's comment on current issue
62 |     userComments.push(...userCommentsOnIssue) // flatten and store the array
63 |   })
64 |   // userComments hold all his comments on all issues
65 |   return userComments
66 | }
67 | 
68 | 69 |
70 | 71 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /docs/file/lib/github-api/createDiscussionIssue.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | lib/github-api/createDiscussionIssue.js | background-finder 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | Home 16 | 17 | Reference 18 | Source 19 | 20 | 27 |
28 | 29 | 35 | 36 |

lib/github-api/createDiscussionIssue.js

37 |
module.exports = (context, { owner, username, toxicComments }) => {
38 |   toxicComments.sort((a, b) => b.toxicScore - a.toxicScore) // sort in decreasing toxicScore order
39 |   const toxicDataText = toxicComments.map(({ link, text, toxicScore }) => `
40 |    1. ${link} has a toxicity rating of **${toxicScore}** :
41 |    
42 |        > ${text}
43 |   `).join('\n')
44 | 
45 |   return context.github.issues.create({
46 |     owner,
47 |     repo: 'maintainers-discussion',
48 |     title: `${username}-discussion`,
49 |     body: `Some comments from @${username} have been found to be toxic. Review the following comments and discuss whether or not you would like to allow this contributor to participate in your community.
50 | 
51 | ${toxicDataText}`
52 |   })
53 | }
54 | 
55 | 56 |
57 | 58 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /docs/file/lib/github-api/getCommentsOnIssue.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | lib/github-api/getCommentsOnIssue.js | background-finder 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | Home 16 | 17 | Reference 18 | Source 19 | 20 | 27 |
28 | 29 | 35 | 36 |

lib/github-api/getCommentsOnIssue.js

37 |
module.exports = (context, { owner, repo, issueNum }) => {
38 |   return context.github.issues.getComments({
39 |     owner,
40 |     repo,
41 |     number: issueNum
42 |   })
43 | }
44 | 
45 | 46 |
47 | 48 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /docs/file/lib/github-api/getUserCommentedIssues.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | lib/github-api/getUserCommentedIssues.js | background-finder 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | Home 16 | 17 | Reference 18 | Source 19 | 20 | 27 |
28 | 29 | 35 | 36 |

lib/github-api/getUserCommentedIssues.js

37 |
module.exports = (context, { username }) => {
38 |   return context.github.search.issues({
39 |     q: `commenter:${username}`
40 |   })
41 | }
42 | 
43 | 44 |
45 | 46 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /docs/file/lib/github-api/getUserDiscussionIssue.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | lib/github-api/getUserDiscussionIssue.js | background-finder 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | Home 16 | 17 | Reference 18 | Source 19 | 20 | 27 |
28 | 29 | 35 | 36 |

lib/github-api/getUserDiscussionIssue.js

37 |
module.exports = (context, { owner, username }) => {
38 |   return context.github.search.issues({
39 |     q: `repo:${owner}/maintainers-discussion is:issue is:open in:title ${username}-discussion`
40 |   })
41 | }
42 | 
43 | 44 |
45 | 46 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /docs/file/lib/utils/analyseSentiment.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | lib/utils/analyseSentiment.js | background-finder 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | Home 16 | 17 | Reference 18 | Source 19 | 20 | 27 |
28 | 29 | 35 | 36 |

lib/utils/analyseSentiment.js

37 |
module.exports = (perspectiveApiKey, { dependencies: { request } }) => {
38 |   const BASE_URL = 'https://commentanalyzer.googleapis.com/v1alpha1'
39 |   const API_URL = `${BASE_URL}/comments:analyze?key=${perspectiveApiKey}`
40 | 
41 |   const analyseSentiment = async (text) => {
42 |     if (!text) return -1
43 |     const textLength = text.length
44 |     if (textLength < 1 || textLength > 3000) return -1 // perspective api text limit 3000B
45 |     try {
46 |       const response = await request.post(API_URL)
47 |       .set('Content-Type', 'application/json')
48 |       .send({
49 |         comment: { text },
50 |         languages: ['en'],
51 |         requestedAttributes: { TOXICITY: {} }
52 |       })
53 | 
54 |       const score = response.body.attributeScores.TOXICITY.summaryScore.value
55 |       return score
56 |     } catch (err) {
57 |       console.log('err', err)
58 |       return -1
59 |     }
60 |   }
61 | 
62 |   return analyseSentiment
63 | }
64 | 
65 | 66 |
67 | 68 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /docs/file/lib/utils/extractRepoDetailsFromUrl.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | lib/utils/extractRepoDetailsFromUrl.js | background-finder 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | Home 16 | 17 | Reference 18 | Source 19 | 20 | 27 |
28 | 29 | 35 | 36 |

lib/utils/extractRepoDetailsFromUrl.js

37 |
module.exports = (repoUrl) => {
38 |   const lastSlashIndex = repoUrl.lastIndexOf('/')
39 |   const repo = repoUrl.substr(lastSlashIndex + 1)
40 |   const repoRemovedUrl = repoUrl.slice(0, lastSlashIndex)
41 |   const secondLastSlashIndex = repoRemovedUrl.lastIndexOf('/')
42 |   const owner = repoRemovedUrl.substr(secondLastSlashIndex + 1)
43 |   return { owner, repo }
44 | }
45 | 
46 | 47 |
48 | 49 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /docs/file/lib/utils/filterUserComments.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | lib/utils/filterUserComments.js | background-finder 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | Home 16 | 17 | Reference 18 | Source 19 | 20 | 27 |
28 | 29 | 35 | 36 |

lib/utils/filterUserComments.js

37 |
module.exports = (comments, username) => {
38 |   const userComments = comments.filter(comment => comment.user.login === username)
39 |   return userComments
40 | }
41 | 
42 | 43 |
44 | 45 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /docs/file/lib/utils/getBinarySize.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | lib/utils/getBinarySize.js | background-finder 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | Home 16 | 17 | Reference 18 | Source 19 | 20 | 27 |
28 | 29 | 35 | 36 |

lib/utils/getBinarySize.js

37 |
function getBinarySize (s) {
38 |   return Buffer.byteLength(s, 'utf16')
39 | }
40 | 
41 | module.exports = getBinarySize
42 | 
43 | 44 |
45 | 46 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /docs/identifiers.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Reference | background-finder 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | Home 16 | 17 | Reference 18 | Source 19 | 20 | 27 |
28 | 29 | 35 | 36 |

References

37 | 38 |
39 |
40 | 41 |
42 | 43 | 44 |
45 |
46 | 47 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /docs/image/badge.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | document 13 | document 14 | @ratio@ 15 | @ratio@ 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/image/esdoc-logo-mini-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itaditya/background-check/dcfbe379d1618807b80696ce25d3771cabc64537/docs/image/esdoc-logo-mini-black.png -------------------------------------------------------------------------------- /docs/image/esdoc-logo-mini.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itaditya/background-check/dcfbe379d1618807b80696ce25d3771cabc64537/docs/image/esdoc-logo-mini.png -------------------------------------------------------------------------------- /docs/image/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itaditya/background-check/dcfbe379d1618807b80696ce25d3771cabc64537/docs/image/github.png -------------------------------------------------------------------------------- /docs/image/manual-badge.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | manual 13 | manual 14 | @value@ 15 | @value@ 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/image/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itaditya/background-check/dcfbe379d1618807b80696ce25d3771cabc64537/docs/image/search.png -------------------------------------------------------------------------------- /docs/lint.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /docs/script/inherited-summary.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | function toggle(ev) { 3 | var button = ev.target; 4 | var parent = ev.target.parentElement; 5 | while(parent) { 6 | if (parent.tagName === 'TABLE' && parent.classList.contains('summary')) break; 7 | parent = parent.parentElement; 8 | } 9 | 10 | if (!parent) return; 11 | 12 | var tbody = parent.querySelector('tbody'); 13 | if (button.classList.contains('opened')) { 14 | button.classList.remove('opened'); 15 | button.classList.add('closed'); 16 | tbody.style.display = 'none'; 17 | } else { 18 | button.classList.remove('closed'); 19 | button.classList.add('opened'); 20 | tbody.style.display = 'block'; 21 | } 22 | } 23 | 24 | var buttons = document.querySelectorAll('.inherited-summary thead .toggle'); 25 | for (var i = 0; i < buttons.length; i++) { 26 | buttons[i].addEventListener('click', toggle); 27 | } 28 | })(); 29 | -------------------------------------------------------------------------------- /docs/script/inner-link.js: -------------------------------------------------------------------------------- 1 | // inner link(#foo) can not correctly scroll, because page has fixed header, 2 | // so, I manually scroll. 3 | (function(){ 4 | var matched = location.hash.match(/errorLines=([\d,]+)/); 5 | if (matched) return; 6 | 7 | function adjust() { 8 | window.scrollBy(0, -55); 9 | var el = document.querySelector('.inner-link-active'); 10 | if (el) el.classList.remove('inner-link-active'); 11 | 12 | // ``[ ] . ' " @`` are not valid in DOM id. so must escape these. 13 | var id = location.hash.replace(/([\[\].'"@$])/g, '\\$1'); 14 | var el = document.querySelector(id); 15 | if (el) el.classList.add('inner-link-active'); 16 | } 17 | 18 | window.addEventListener('hashchange', adjust); 19 | 20 | if (location.hash) { 21 | setTimeout(adjust, 0); 22 | } 23 | })(); 24 | 25 | (function(){ 26 | var els = document.querySelectorAll('[href^="#"]'); 27 | var href = location.href.replace(/#.*$/, ''); // remove existed hash 28 | for (var i = 0; i < els.length; i++) { 29 | var el = els[i]; 30 | el.href = href + el.getAttribute('href'); // because el.href is absolute path 31 | } 32 | })(); 33 | -------------------------------------------------------------------------------- /docs/script/manual.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | var matched = location.pathname.match(/\/(manual\/.*\.html)$/); 3 | if (!matched) return; 4 | 5 | var currentName = matched[1]; 6 | var cssClass = '.navigation .manual-toc li[data-link="' + currentName + '"]'; 7 | var styleText = cssClass + '{ display: block; }\n'; 8 | styleText += cssClass + '.indent-h1 a { color: #039BE5 }'; 9 | var style = document.createElement('style'); 10 | style.textContent = styleText; 11 | document.querySelector('head').appendChild(style); 12 | })(); 13 | -------------------------------------------------------------------------------- /docs/script/patch-for-local.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | if (location.protocol === 'file:') { 3 | var elms = document.querySelectorAll('a[href="./"]'); 4 | for (var i = 0; i < elms.length; i++) { 5 | elms[i].href = './index.html'; 6 | } 7 | } 8 | })(); 9 | -------------------------------------------------------------------------------- /docs/script/prettify/Apache-License-2.0.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /docs/script/pretty-print.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | prettyPrint(); 3 | var lines = document.querySelectorAll('.prettyprint.linenums li[class^="L"]'); 4 | for (var i = 0; i < lines.length; i++) { 5 | lines[i].id = 'lineNumber' + (i + 1); 6 | } 7 | 8 | var matched = location.hash.match(/errorLines=([\d,]+)/); 9 | if (matched) { 10 | var lines = matched[1].split(','); 11 | for (var i = 0; i < lines.length; i++) { 12 | var id = '#lineNumber' + lines[i]; 13 | var el = document.querySelector(id); 14 | el.classList.add('error-line'); 15 | } 16 | return; 17 | } 18 | 19 | if (location.hash) { 20 | // ``[ ] . ' " @`` are not valid in DOM id. so must escape these. 21 | var id = location.hash.replace(/([\[\].'"@$])/g, '\\$1'); 22 | var line = document.querySelector(id); 23 | if (line) line.classList.add('active'); 24 | } 25 | })(); 26 | -------------------------------------------------------------------------------- /docs/script/search.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | var searchIndex = window.esdocSearchIndex; 3 | var searchBox = document.querySelector('.search-box'); 4 | var input = document.querySelector('.search-input'); 5 | var result = document.querySelector('.search-result'); 6 | var selectedIndex = -1; 7 | var prevText; 8 | 9 | // active search box and focus when mouse enter on search box. 10 | searchBox.addEventListener('mouseenter', function(){ 11 | searchBox.classList.add('active'); 12 | input.focus(); 13 | }); 14 | 15 | // search with text when key is upped. 16 | input.addEventListener('keyup', function(ev){ 17 | var text = ev.target.value.toLowerCase(); 18 | if (!text) { 19 | result.style.display = 'none'; 20 | result.innerHTML = ''; 21 | return; 22 | } 23 | 24 | if (text === prevText) return; 25 | prevText = text; 26 | 27 | var html = {class: [], method: [], member: [], function: [], variable: [], typedef: [], external: [], file: [], test: [], testFile: []}; 28 | var len = searchIndex.length; 29 | var kind; 30 | for (var i = 0; i < len; i++) { 31 | var pair = searchIndex[i]; 32 | if (pair[0].indexOf(text) !== -1) { 33 | kind = pair[3]; 34 | html[kind].push('
  • ' + pair[2] + '
  • '); 35 | } 36 | } 37 | 38 | var innerHTML = ''; 39 | for (kind in html) { 40 | var list = html[kind]; 41 | if (!list.length) continue; 42 | innerHTML += '
  • ' + kind + '
  • \n' + list.join('\n'); 43 | } 44 | result.innerHTML = innerHTML; 45 | if (innerHTML) result.style.display = 'block'; 46 | selectedIndex = -1; 47 | }); 48 | 49 | // down, up and enter key are pressed, select search result. 50 | input.addEventListener('keydown', function(ev){ 51 | if (ev.keyCode === 40) { 52 | // arrow down 53 | var current = result.children[selectedIndex]; 54 | var selected = result.children[selectedIndex + 1]; 55 | if (selected && selected.classList.contains('search-separator')) { 56 | var selected = result.children[selectedIndex + 2]; 57 | selectedIndex++; 58 | } 59 | 60 | if (selected) { 61 | if (current) current.classList.remove('selected'); 62 | selectedIndex++; 63 | selected.classList.add('selected'); 64 | } 65 | } else if (ev.keyCode === 38) { 66 | // arrow up 67 | var current = result.children[selectedIndex]; 68 | var selected = result.children[selectedIndex - 1]; 69 | if (selected && selected.classList.contains('search-separator')) { 70 | var selected = result.children[selectedIndex - 2]; 71 | selectedIndex--; 72 | } 73 | 74 | if (selected) { 75 | if (current) current.classList.remove('selected'); 76 | selectedIndex--; 77 | selected.classList.add('selected'); 78 | } 79 | } else if (ev.keyCode === 13) { 80 | // enter 81 | var current = result.children[selectedIndex]; 82 | if (current) { 83 | var link = current.querySelector('a'); 84 | if (link) location.href = link.href; 85 | } 86 | } else { 87 | return; 88 | } 89 | 90 | ev.preventDefault(); 91 | }); 92 | 93 | // select search result when search result is mouse over. 94 | result.addEventListener('mousemove', function(ev){ 95 | var current = result.children[selectedIndex]; 96 | if (current) current.classList.remove('selected'); 97 | 98 | var li = ev.target; 99 | while (li) { 100 | if (li.nodeName === 'LI') break; 101 | li = li.parentElement; 102 | } 103 | 104 | if (li) { 105 | selectedIndex = Array.prototype.indexOf.call(result.children, li); 106 | li.classList.add('selected'); 107 | } 108 | }); 109 | 110 | // clear search result when body is clicked. 111 | document.body.addEventListener('click', function(ev){ 112 | selectedIndex = -1; 113 | result.style.display = 'none'; 114 | result.innerHTML = ''; 115 | }); 116 | 117 | })(); 118 | -------------------------------------------------------------------------------- /docs/script/search_index.js: -------------------------------------------------------------------------------- 1 | window.esdocSearchIndex = [ 2 | [ 3 | "lib/.external-ecmascript.js~array", 4 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array", 5 | "lib/.external-ecmascript.js~Array", 6 | "external" 7 | ], 8 | [ 9 | "lib/.external-ecmascript.js~arraybuffer", 10 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer", 11 | "lib/.external-ecmascript.js~ArrayBuffer", 12 | "external" 13 | ], 14 | [ 15 | "lib/.external-ecmascript.js~boolean", 16 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean", 17 | "lib/.external-ecmascript.js~Boolean", 18 | "external" 19 | ], 20 | [ 21 | "lib/.external-ecmascript.js~dataview", 22 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView", 23 | "lib/.external-ecmascript.js~DataView", 24 | "external" 25 | ], 26 | [ 27 | "lib/.external-ecmascript.js~date", 28 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date", 29 | "lib/.external-ecmascript.js~Date", 30 | "external" 31 | ], 32 | [ 33 | "lib/.external-ecmascript.js~error", 34 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error", 35 | "lib/.external-ecmascript.js~Error", 36 | "external" 37 | ], 38 | [ 39 | "lib/.external-ecmascript.js~evalerror", 40 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/EvalError", 41 | "lib/.external-ecmascript.js~EvalError", 42 | "external" 43 | ], 44 | [ 45 | "lib/.external-ecmascript.js~float32array", 46 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float32Array", 47 | "lib/.external-ecmascript.js~Float32Array", 48 | "external" 49 | ], 50 | [ 51 | "lib/.external-ecmascript.js~float64array", 52 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float64Array", 53 | "lib/.external-ecmascript.js~Float64Array", 54 | "external" 55 | ], 56 | [ 57 | "lib/.external-ecmascript.js~function", 58 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function", 59 | "lib/.external-ecmascript.js~Function", 60 | "external" 61 | ], 62 | [ 63 | "lib/.external-ecmascript.js~generator", 64 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator", 65 | "lib/.external-ecmascript.js~Generator", 66 | "external" 67 | ], 68 | [ 69 | "lib/.external-ecmascript.js~generatorfunction", 70 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/GeneratorFunction", 71 | "lib/.external-ecmascript.js~GeneratorFunction", 72 | "external" 73 | ], 74 | [ 75 | "lib/.external-ecmascript.js~infinity", 76 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Infinity", 77 | "lib/.external-ecmascript.js~Infinity", 78 | "external" 79 | ], 80 | [ 81 | "lib/.external-ecmascript.js~int16array", 82 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Int16Array", 83 | "lib/.external-ecmascript.js~Int16Array", 84 | "external" 85 | ], 86 | [ 87 | "lib/.external-ecmascript.js~int32array", 88 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Int32Array", 89 | "lib/.external-ecmascript.js~Int32Array", 90 | "external" 91 | ], 92 | [ 93 | "lib/.external-ecmascript.js~int8array", 94 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Int8Array", 95 | "lib/.external-ecmascript.js~Int8Array", 96 | "external" 97 | ], 98 | [ 99 | "lib/.external-ecmascript.js~internalerror", 100 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/InternalError", 101 | "lib/.external-ecmascript.js~InternalError", 102 | "external" 103 | ], 104 | [ 105 | "lib/.external-ecmascript.js~json", 106 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON", 107 | "lib/.external-ecmascript.js~JSON", 108 | "external" 109 | ], 110 | [ 111 | "lib/.external-ecmascript.js~map", 112 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map", 113 | "lib/.external-ecmascript.js~Map", 114 | "external" 115 | ], 116 | [ 117 | "lib/.external-ecmascript.js~nan", 118 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN", 119 | "lib/.external-ecmascript.js~NaN", 120 | "external" 121 | ], 122 | [ 123 | "lib/.external-ecmascript.js~number", 124 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number", 125 | "lib/.external-ecmascript.js~Number", 126 | "external" 127 | ], 128 | [ 129 | "lib/.external-ecmascript.js~object", 130 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object", 131 | "lib/.external-ecmascript.js~Object", 132 | "external" 133 | ], 134 | [ 135 | "lib/.external-ecmascript.js~promise", 136 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise", 137 | "lib/.external-ecmascript.js~Promise", 138 | "external" 139 | ], 140 | [ 141 | "lib/.external-ecmascript.js~proxy", 142 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy", 143 | "lib/.external-ecmascript.js~Proxy", 144 | "external" 145 | ], 146 | [ 147 | "lib/.external-ecmascript.js~rangeerror", 148 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RangeError", 149 | "lib/.external-ecmascript.js~RangeError", 150 | "external" 151 | ], 152 | [ 153 | "lib/.external-ecmascript.js~referenceerror", 154 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ReferenceError", 155 | "lib/.external-ecmascript.js~ReferenceError", 156 | "external" 157 | ], 158 | [ 159 | "lib/.external-ecmascript.js~reflect", 160 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect", 161 | "lib/.external-ecmascript.js~Reflect", 162 | "external" 163 | ], 164 | [ 165 | "lib/.external-ecmascript.js~regexp", 166 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp", 167 | "lib/.external-ecmascript.js~RegExp", 168 | "external" 169 | ], 170 | [ 171 | "lib/.external-ecmascript.js~set", 172 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set", 173 | "lib/.external-ecmascript.js~Set", 174 | "external" 175 | ], 176 | [ 177 | "lib/.external-ecmascript.js~string", 178 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String", 179 | "lib/.external-ecmascript.js~String", 180 | "external" 181 | ], 182 | [ 183 | "lib/.external-ecmascript.js~symbol", 184 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol", 185 | "lib/.external-ecmascript.js~Symbol", 186 | "external" 187 | ], 188 | [ 189 | "lib/.external-ecmascript.js~syntaxerror", 190 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SyntaxError", 191 | "lib/.external-ecmascript.js~SyntaxError", 192 | "external" 193 | ], 194 | [ 195 | "lib/.external-ecmascript.js~typeerror", 196 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypeError", 197 | "lib/.external-ecmascript.js~TypeError", 198 | "external" 199 | ], 200 | [ 201 | "lib/.external-ecmascript.js~urierror", 202 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/URIError", 203 | "lib/.external-ecmascript.js~URIError", 204 | "external" 205 | ], 206 | [ 207 | "lib/.external-ecmascript.js~uint16array", 208 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint16Array", 209 | "lib/.external-ecmascript.js~Uint16Array", 210 | "external" 211 | ], 212 | [ 213 | "lib/.external-ecmascript.js~uint32array", 214 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint32Array", 215 | "lib/.external-ecmascript.js~Uint32Array", 216 | "external" 217 | ], 218 | [ 219 | "lib/.external-ecmascript.js~uint8array", 220 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array", 221 | "lib/.external-ecmascript.js~Uint8Array", 222 | "external" 223 | ], 224 | [ 225 | "lib/.external-ecmascript.js~uint8clampedarray", 226 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8ClampedArray", 227 | "lib/.external-ecmascript.js~Uint8ClampedArray", 228 | "external" 229 | ], 230 | [ 231 | "lib/.external-ecmascript.js~weakmap", 232 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap", 233 | "lib/.external-ecmascript.js~WeakMap", 234 | "external" 235 | ], 236 | [ 237 | "lib/.external-ecmascript.js~weakset", 238 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakSet", 239 | "lib/.external-ecmascript.js~WeakSet", 240 | "external" 241 | ], 242 | [ 243 | "lib/.external-ecmascript.js~boolean", 244 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean", 245 | "lib/.external-ecmascript.js~boolean", 246 | "external" 247 | ], 248 | [ 249 | "lib/.external-ecmascript.js~function", 250 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function", 251 | "lib/.external-ecmascript.js~function", 252 | "external" 253 | ], 254 | [ 255 | "lib/.external-ecmascript.js~null", 256 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/null", 257 | "lib/.external-ecmascript.js~null", 258 | "external" 259 | ], 260 | [ 261 | "lib/.external-ecmascript.js~number", 262 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number", 263 | "lib/.external-ecmascript.js~number", 264 | "external" 265 | ], 266 | [ 267 | "lib/.external-ecmascript.js~object", 268 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object", 269 | "lib/.external-ecmascript.js~object", 270 | "external" 271 | ], 272 | [ 273 | "lib/.external-ecmascript.js~string", 274 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String", 275 | "lib/.external-ecmascript.js~string", 276 | "external" 277 | ], 278 | [ 279 | "lib/.external-ecmascript.js~undefined", 280 | "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/undefined", 281 | "lib/.external-ecmascript.js~undefined", 282 | "external" 283 | ], 284 | [ 285 | "lib/backgroundfinder.js", 286 | "file/lib/backgroundFinder.js.html", 287 | "lib/backgroundFinder.js", 288 | "file" 289 | ], 290 | [ 291 | "lib/getpubliccomments.js", 292 | "file/lib/getPublicComments.js.html", 293 | "lib/getPublicComments.js", 294 | "file" 295 | ], 296 | [ 297 | "lib/github-api/creatediscussionissue.js", 298 | "file/lib/github-api/createDiscussionIssue.js.html", 299 | "lib/github-api/createDiscussionIssue.js", 300 | "file" 301 | ], 302 | [ 303 | "lib/github-api/getcommentsonissue.js", 304 | "file/lib/github-api/getCommentsOnIssue.js.html", 305 | "lib/github-api/getCommentsOnIssue.js", 306 | "file" 307 | ], 308 | [ 309 | "lib/github-api/getusercommentedissues.js", 310 | "file/lib/github-api/getUserCommentedIssues.js.html", 311 | "lib/github-api/getUserCommentedIssues.js", 312 | "file" 313 | ], 314 | [ 315 | "lib/github-api/getuserdiscussionissue.js", 316 | "file/lib/github-api/getUserDiscussionIssue.js.html", 317 | "lib/github-api/getUserDiscussionIssue.js", 318 | "file" 319 | ], 320 | [ 321 | "lib/utils/analysesentiment.js", 322 | "file/lib/utils/analyseSentiment.js.html", 323 | "lib/utils/analyseSentiment.js", 324 | "file" 325 | ], 326 | [ 327 | "lib/utils/extractrepodetailsfromurl.js", 328 | "file/lib/utils/extractRepoDetailsFromUrl.js.html", 329 | "lib/utils/extractRepoDetailsFromUrl.js", 330 | "file" 331 | ], 332 | [ 333 | "lib/utils/filterusercomments.js", 334 | "file/lib/utils/filterUserComments.js.html", 335 | "lib/utils/filterUserComments.js", 336 | "file" 337 | ], 338 | [ 339 | "lib/utils/getbinarysize.js", 340 | "file/lib/utils/getBinarySize.js.html", 341 | "lib/utils/getBinarySize.js", 342 | "file" 343 | ] 344 | ] -------------------------------------------------------------------------------- /docs/script/test-summary.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | function toggle(ev) { 3 | var button = ev.target; 4 | var parent = ev.target.parentElement; 5 | while(parent) { 6 | if (parent.tagName === 'TR' && parent.classList.contains('test-interface')) break; 7 | parent = parent.parentElement; 8 | } 9 | 10 | if (!parent) return; 11 | 12 | var direction; 13 | if (button.classList.contains('opened')) { 14 | button.classList.remove('opened'); 15 | button.classList.add('closed'); 16 | direction = 'closed'; 17 | } else { 18 | button.classList.remove('closed'); 19 | button.classList.add('opened'); 20 | direction = 'opened'; 21 | } 22 | 23 | var targetDepth = parseInt(parent.dataset.testDepth, 10) + 1; 24 | var nextElement = parent.nextElementSibling; 25 | while (nextElement) { 26 | var depth = parseInt(nextElement.dataset.testDepth, 10); 27 | if (depth >= targetDepth) { 28 | if (direction === 'opened') { 29 | if (depth === targetDepth) nextElement.style.display = ''; 30 | } else if (direction === 'closed') { 31 | nextElement.style.display = 'none'; 32 | var innerButton = nextElement.querySelector('.toggle'); 33 | if (innerButton && innerButton.classList.contains('opened')) { 34 | innerButton.classList.remove('opened'); 35 | innerButton.classList.add('closed'); 36 | } 37 | } 38 | } else { 39 | break; 40 | } 41 | nextElement = nextElement.nextElementSibling; 42 | } 43 | } 44 | 45 | var buttons = document.querySelectorAll('.test-summary tr.test-interface .toggle'); 46 | for (var i = 0; i < buttons.length; i++) { 47 | buttons[i].addEventListener('click', toggle); 48 | } 49 | 50 | var topDescribes = document.querySelectorAll('.test-summary tr[data-test-depth="0"]'); 51 | for (var i = 0; i < topDescribes.length; i++) { 52 | topDescribes[i].style.display = ''; 53 | } 54 | })(); 55 | -------------------------------------------------------------------------------- /docs/source.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Source | background-finder 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
    15 | Home 16 | 17 | Reference 18 | Source 19 | 20 | 27 |
    28 | 29 | 35 | 36 |

    Source 0/7

    37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 |
    FileIdentifierDocumentSizeLinesUpdated
    lib/backgroundFinder.js--3029 byte732018-06-02 12:08:38 (UTC)
    lib/getPublicComments.js-0 %0/61434 byte302018-05-04 14:12:16 (UTC)
    lib/github-api/createDiscussionIssue.js--711 byte172018-06-01 07:14:02 (UTC)
    lib/github-api/getCommentsOnIssue.js--153 byte72018-05-03 14:52:55 (UTC)
    lib/github-api/getUserCommentedIssues.js--124 byte52018-05-03 09:08:13 (UTC)
    lib/github-api/getUserDiscussionIssue.js--200 byte52018-06-07 14:29:52 (UTC)
    lib/utils/analyseSentiment.js--874 byte272018-05-03 09:25:44 (UTC)
    lib/utils/extractRepoDetailsFromUrl.js--344 byte82018-05-04 09:40:52 (UTC)
    lib/utils/filterUserComments.js--150 byte42018-05-07 22:08:39 (UTC)
    lib/utils/getBinarySize.js-0 %0/1102 byte52018-05-07 19:47:43 (UTC)
    133 |
    134 | 135 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config() 2 | const request = require('superagent') 3 | const githubClient = require('probot/lib/github')() 4 | 5 | const extractRepoDetails = require('./lib/utils/extractRepoDetailsFromUrl') 6 | const analyseSentiment = require('./lib/utils/analyseSentiment') 7 | const getUserDiscussionIssue = require('./lib/github-api/getUserDiscussionIssue') 8 | const getUserCommentedIssues = require('./lib/github-api/getUserCommentedIssues') 9 | const getCommentsOnIssue = require('./lib/github-api/getCommentsOnIssue') 10 | const createDiscussionIssue = require('./lib/github-api/createDiscussionIssue') 11 | const createDiscussionRepo = require('./lib/github-api/createDiscussionRepo') 12 | const addCollaboratorToRepo = require('./lib/github-api/addCollaboratorToRepo') 13 | 14 | const { PERSPECTIVE_API_KEY, GITHUB_ACCESS_TOKEN } = process.env 15 | const sentimentAnalyser = analyseSentiment(PERSPECTIVE_API_KEY, { 16 | dependencies: { request } 17 | }) 18 | githubClient.authenticate({ 19 | type: 'token', 20 | token: GITHUB_ACCESS_TOKEN 21 | }) 22 | 23 | const backgroundFinder = require('./lib/backgroundFinder')({ 24 | dependencies: { 25 | extractRepoDetails, 26 | getUserDiscussionIssue, 27 | getUserCommentedIssues, 28 | getCommentsOnIssue, 29 | sentimentAnalyser, 30 | createDiscussionIssue 31 | } 32 | }) 33 | 34 | const discussionBoardSetup = require('./lib/discussionBoardSetup')({ 35 | dependencies: { 36 | createDiscussionRepo, 37 | addCollaboratorToRepo, 38 | githubClient 39 | } 40 | }) 41 | 42 | module.exports = (robot) => { 43 | robot.log('bot started') 44 | 45 | robot.on('installation.created', context => { 46 | console.log('hello') 47 | discussionBoardSetup(context) 48 | }) 49 | 50 | robot.on('issue_comment.created', context => { 51 | context.log('event received') 52 | context.log('repo details', context.repo()) 53 | backgroundFinder(context) 54 | }) 55 | } 56 | -------------------------------------------------------------------------------- /lib/backgroundFinder.js: -------------------------------------------------------------------------------- 1 | /** 2 | * backgroundFinder module 3 | * @param {object} params 4 | * @param {object} params.dependencies - accepts the dependecies following **dependency inversion principle**. 5 | * @param {extractRepoDetails} params.dependencies.extractRepoDetails - utility to extract owner and repo name from **repoUrl**. 6 | * @param {getUserDiscussionIssue} params.dependencies.getUserDiscussionIssue - github-api method to search issue for user in maintainers-discussion repo. 7 | * @param {getUserCommentedIssues} params.dependencies.getUserCommentedIssues - github-api method to search issues on which user commented. 8 | * @param {getCommentsOnIssue} params.dependencies.getCommentsOnIssue - github-api method to fetch comments of an issue. 9 | * @param {sentimentAnalyser} params.dependencies.sentimentAnalyser - utility to analyse sentiment of a comment. 10 | * @param {createDiscussionIssue} params.dependencies.createDiscussionIssue - github-api method to create issue for a hostile user in **maintainers-discussion** repo. 11 | * @returns {backgroundFinder} 12 | * @example 13 | * const backgroundFinder = backgroundFinderModule({ dependencies: {} }) 14 | */ 15 | 16 | const backgroundFinderModule = ({ dependencies: { extractRepoDetails, getUserDiscussionIssue, getUserCommentedIssues, getCommentsOnIssue, sentimentAnalyser, createDiscussionIssue } }) => { 17 | /** 18 | * backgroundFinder method 19 | * @param {object} context - context argument. 20 | * @returns {promise} 21 | * @example 22 | * await backgroundFinder(context) 23 | */ 24 | const backgroundFinder = async(context) => { 25 | if (context.isBot) return 26 | const { github } = context 27 | const owner = context.payload.repository.owner.login 28 | const username = context.payload.comment.user.login 29 | context.log(`Analyis for ${username} has started`) 30 | 31 | /* -- Check if user is already found hostile -- */ 32 | const userIssueResult = await getUserDiscussionIssue(github, { owner, username }) 33 | const alreadyFoundHostile = userIssueResult.data.total_count >= 1 34 | if (alreadyFoundHostile) { 35 | context.log(`${username} has already been found hostile before.\nTerminating ${username}'s analysis.`) 36 | return 37 | } 38 | /* ^- -^ */ 39 | 40 | context.log(`${username} has not been found hostile before. \nCollection of Public Comments starting.`) 41 | const issuesResult = await getUserCommentedIssues(github, { username }) 42 | const { data: { items: issues } } = issuesResult 43 | const userToxicComments = [] 44 | let userToxicCommentsLimit = 3 45 | let totalUserComments = 0 46 | 47 | for (let issue of issues) { 48 | // for each issue in search result 49 | const issueNum = issue.number 50 | const repoUrl = issue.repository_url 51 | context.log(`Fetching comments on ${issue.url}`) 52 | const { data: commentsOnIssue } = await getCommentsOnIssue(github, { issueNum, ...extractRepoDetails(repoUrl) }) 53 | 54 | // we'll get 30 comments on issueNum issue 55 | const userCommentsOnIssue = [] // stores only the username's comments 56 | for (let comment of commentsOnIssue) { 57 | if (comment.user.type !== 'Bot' && comment.user.login === username) { 58 | userCommentsOnIssue.push(comment) 59 | } 60 | } 61 | totalUserComments += userCommentsOnIssue.length 62 | 63 | let commentBlob = userCommentsOnIssue.map(comment => comment.body).join('.\n') 64 | if (commentBlob.length <= 0) continue // empty commentBlob 65 | 66 | const toxicScore = await sentimentAnalyser(commentBlob.substr(0, 3000)) // perspective api limits the text size to 3000B 67 | const isToxic = toxicScore >= 0.6 68 | context.log('toxicScore is', toxicScore) 69 | if (isToxic) { 70 | userToxicCommentsLimit -= 1 71 | userToxicComments.push({ 72 | link: issue.html_url, 73 | text: commentBlob, 74 | toxicScore 75 | }) 76 | } 77 | 78 | if (userToxicCommentsLimit <= 0) { 79 | const { data: discussionIssueData } = await createDiscussionIssue(github, { username, owner, toxicComments: userToxicComments }) 80 | context.log(`Discussion issue for ${username} has been created. Check out ${discussionIssueData.html_url}`) 81 | context.log(`${username}'s ${totalUserComments} comments were analysed`) 82 | break 83 | } 84 | 85 | if (totalUserComments > 100) { 86 | context.log(`More than 100 comments of ${username} have been analyzed & it is concluded that he is not hostile.`) 87 | break 88 | } 89 | } 90 | } 91 | 92 | return backgroundFinder 93 | } 94 | 95 | module.exports = backgroundFinderModule 96 | -------------------------------------------------------------------------------- /lib/discussionBoardSetup.js: -------------------------------------------------------------------------------- 1 | /** 2 | * discussionBoardSetup module 3 | * @param {object} params 4 | * @param {object} params.dependencies - accepts the dependecies following **dependency inversion principle**. 5 | * @param {createDiscussionRepo} params.dependencies.createDiscussionRepo - github-api method to create private discussion repo for the app installer 6 | * @param {addCollaboratorToRepo} params.dependencies.addCollaboratorToRepo - github-api method to add collborator to discussion repo 7 | * @param {githubClient} params.dependencies.githubClient - authenticated githubClient with correct permissions 8 | * @returns {discussionBoardSetup} 9 | * @example 10 | * const discussionBoardSetup = discussionBoardSetupModule({ dependencies: {} }) 11 | */ 12 | 13 | const discussionBoardSetupModule = ({ dependencies: { createDiscussionRepo, addCollaboratorToRepo, githubClient } }) => { 14 | /** 15 | * discussionBoardSetup method 16 | * @param {object} context - context argument. 17 | * @returns {promise} 18 | * @example 19 | * await discussionBoardSetup(context) 20 | */ 21 | const discussionBoardSetup = async (context) => { 22 | const appInstallerName = context.payload.installation.account.login 23 | const sender = context.payload.sender.login 24 | try { 25 | context.log(`Creating discussion board for ${appInstallerName}`) 26 | await createDiscussionRepo(githubClient, { appInstallerName }) 27 | context.log(`Discussion board for ${appInstallerName} has been setup successfully`) 28 | try { 29 | context.log(`Adding ${sender} as collaborator to ${appInstallerName}-discussions repo`) 30 | await addCollaboratorToRepo(githubClient, { appInstallerName, username: sender }) 31 | context.log(`Successfully added ${sender} as collaborator`) 32 | } catch (error) { 33 | context.log(`Error in adding ${sender} as collaborator to ${appInstallerName}-discussions repo`) 34 | context.log(error) 35 | } 36 | } catch (error) { 37 | context.log(`Error in creating discussion board for ${appInstallerName}`) 38 | context.log(error) 39 | } 40 | } 41 | 42 | return discussionBoardSetup 43 | } 44 | 45 | module.exports = discussionBoardSetupModule 46 | -------------------------------------------------------------------------------- /lib/getPublicComments.js: -------------------------------------------------------------------------------- 1 | const extractRepoDetails = require('./utils/extractRepoDetailsFromUrl') 2 | const filterUserComments = require('./utils/filterUserComments') 3 | const getUserCommentedIssues = require('./github-api/getUserCommentedIssues') 4 | const getCommentsOnIssue = require('./github-api/getCommentsOnIssue') 5 | 6 | module.exports = async(context, { username }) => { 7 | const issuesResult = await getUserCommentedIssues(context, { username }) 8 | const { data: { total_count, items: issues } } = issuesResult 9 | console.log('total_count', total_count) 10 | const commentsResults = await getCommentsOnIssues(context, { issues }) 11 | const userComments = getUserComments(commentsResults, username) 12 | return userComments 13 | } 14 | 15 | async function getCommentsOnIssues (context, { issues }) { 16 | const commentsPromises = issues 17 | .map(({ number, repository_url: url }) => getCommentsOnIssue(context, { issueNum: number, ...extractRepoDetails(url) })) 18 | return Promise.all(commentsPromises) 19 | } 20 | 21 | function getUserComments (commentsResults, username) { 22 | const userComments = [] 23 | commentsResults.forEach(({ data: commentsData }) => { 24 | const userCommentsOnIssue = filterUserComments(commentsData, username) 25 | // userCommentsOnIssue is an array holding the wanted user's comment on current issue 26 | userComments.push(...userCommentsOnIssue) // flatten and store the array 27 | }) 28 | // userComments hold all his comments on all issues 29 | return userComments 30 | } 31 | -------------------------------------------------------------------------------- /lib/github-api/addCollaboratorToRepo.js: -------------------------------------------------------------------------------- 1 | /** 2 | * addCollaboratorToRepo github-api method used to add collaborators to **probot-background-check/{{owner}}-maintainers-discussion** repo. 3 | * @param {object} github - authenticated github client 4 | * @param {object} data 5 | * @param {string} data.appInstallerName - individual / org account name on which app is installed 6 | * @param {string} data.username - username of user who installed the app. 7 | * @returns {Promise} 8 | */ 9 | 10 | module.exports = (github, { appInstallerName, username }) => { 11 | return github.repos.addCollaborator({ 12 | username, 13 | owner: process.env.APP_ORG_NAME, 14 | repo: `${appInstallerName}-discussions`, 15 | permission: 'push' 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /lib/github-api/createDiscussionIssue.js: -------------------------------------------------------------------------------- 1 | /** 2 | * createDiscussionIssue github-api method used to open an issue in **probot-background-check/{{owner}}-maintainers-discussion** repo. The issue description will have a list of the toxic comments of user in non increasing order of their toxicity. 3 | * @param {object} github - authenticated github client 4 | * @param {object} data 5 | * @param {string} data.owner - owner of repo 6 | * @param {string} data.username - username to create issue for in the **probot-background-check/{{data.owner}}-maintainers-discussion** repo 7 | * @param {array} data.toxicComments - list of toxicComments of the {{data.username}} user 8 | * @returns {Promise} 9 | */ 10 | 11 | module.exports = (github, { owner, username, toxicComments }) => { 12 | toxicComments.sort((a, b) => b.toxicScore - a.toxicScore) // sort in decreasing toxicScore order 13 | const toxicDataText = toxicComments.map(({ link, text, toxicScore }) => ` 14 | 1. ${link} has a toxicity rating of **${toxicScore}** : 15 | 16 | > ${text} 17 | 18 | `).join('\n') 19 | 20 | return github.issues.create({ 21 | owner: process.env.APP_ORG_NAME, 22 | repo: `${owner}-discussions`, 23 | title: `${username}-discussion`, 24 | body: `Some comments from @${username} have been found to be toxic. Review the following comments and discuss whether or not you would like to allow this contributor to participate in your community. 25 | 26 | ${toxicDataText}` 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /lib/github-api/createDiscussionRepo.js: -------------------------------------------------------------------------------- 1 | /** 2 | * createDiscussionRepo github-api method used to create a discussion repo named **{{appInstallerName}}-discussions** for a user/org in app's org in which discussion for users who have been hostile will be held. 3 | * @param {object} github - authenticated github client 4 | * @param {object} data 5 | * @param {string} data.appInstallerName - name of user/org who installed the app. 6 | * @returns {Promise} 7 | */ 8 | 9 | module.exports = (github, { appInstallerName }) => { 10 | return github.repos.createForOrg({ 11 | org: process.env.APP_ORG_NAME, 12 | name: `${appInstallerName}-discussions`, 13 | description: 'Repo to have discussions about toxic users', 14 | private: true, 15 | auto_init: true 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /lib/github-api/getCommentsOnIssue.js: -------------------------------------------------------------------------------- 1 | /** 2 | * getCommentsOnIssue github-api method used to get a paginated list of comments on an issue. 3 | * @param {object} github - authenticated github client 4 | * @param {object} data 5 | * @param {string} data.owner - owner of repo 6 | * @param {string} data.repo - name of repo 7 | * @param {array} data.issueNum - issue number of the issue in {{data.owner}}/{{data.repo}} repository 8 | * @returns {Promise} 9 | */ 10 | 11 | module.exports = (github, { owner, repo, issueNum }) => { 12 | return github.issues.getComments({ 13 | owner, 14 | repo, 15 | number: issueNum 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /lib/github-api/getUserCommentedIssues.js: -------------------------------------------------------------------------------- 1 | /** 2 | * getUserCommentedIssues **github-api method** used to search for issues in which **{{data.username}}** has commented. 3 | * @param {object} github - authenticated github client 4 | * @param {object} data 5 | * @param {string} data.username - username to search commented isssues for 6 | * @returns {Promise} 7 | */ 8 | 9 | module.exports = (github, { username }) => { 10 | return github.search.issues({ 11 | q: `commenter:${username}` 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /lib/github-api/getUserDiscussionIssue.js: -------------------------------------------------------------------------------- 1 | /** 2 | * getUserDiscussionIssue github-api method 3 | * @param {object} github - authenticated github client 4 | * @param {object} data 5 | * @param {string} data.owner - owner of repo 6 | * @param {string} data.username - username to search open issue for in the **probot-background-check/{{data.owner}}-maintainers-discussion** repo 7 | * @returns {promise} 8 | */ 9 | 10 | module.exports = (github, { owner, username }) => { 11 | return github.search.issues({ 12 | q: `repo:${process.env.APP_ORG_NAME}/${owner}-discussions is:issue is:open in:title ${username}-discussion` 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /lib/utils/analyseSentiment.js: -------------------------------------------------------------------------------- 1 | /** 2 | * analyseSentiment module 3 | * @param {string} perspectiveApiKey - the api access key for Perspective API 4 | * @param {object} params 5 | * @param {object} params.dependencies - accepts the dependecies following **dependency inversion principle**. 6 | * @param {function} params.dependencies.request - lib to make http requests. 7 | * @returns {analyseSentiment} 8 | * @example 9 | * const analyseSentiment = analyseSentimentModule({ dependencies: { request } }) 10 | */ 11 | 12 | const analyseSentimentModule = (perspectiveApiKey, { dependencies: { request } }) => { 13 | const BASE_URL = 'https://commentanalyzer.googleapis.com/v1alpha1' 14 | const API_URL = `${BASE_URL}/comments:analyze?key=${perspectiveApiKey}` 15 | 16 | /** 17 | * analyseSentiment method 18 | * @param {string} text - the text to be analysed. 19 | * @returns {promise} 20 | * @example 21 | * await analyseSentiment('analyse this text') 22 | */ 23 | const analyseSentiment = async (text) => { 24 | if (!text) return -1 25 | const textLength = text.length 26 | if (textLength < 1 || textLength > 3000) return -1 // perspective api text limit 3000B 27 | try { 28 | const response = await request.post(API_URL) 29 | .set('Content-Type', 'application/json') 30 | .send({ 31 | comment: { text }, 32 | languages: ['en'], 33 | requestedAttributes: { TOXICITY: {} } 34 | }) 35 | 36 | const score = response.body.attributeScores.TOXICITY.summaryScore.value 37 | return score 38 | } catch (err) { 39 | console.log('err', err) 40 | return -1 41 | } 42 | } 43 | 44 | return analyseSentiment 45 | } 46 | 47 | module.exports = analyseSentimentModule 48 | -------------------------------------------------------------------------------- /lib/utils/extractRepoDetailsFromUrl.js: -------------------------------------------------------------------------------- 1 | module.exports = (repoUrl) => { 2 | const lastSlashIndex = repoUrl.lastIndexOf('/') 3 | const repo = repoUrl.substr(lastSlashIndex + 1) 4 | const repoRemovedUrl = repoUrl.slice(0, lastSlashIndex) 5 | const secondLastSlashIndex = repoRemovedUrl.lastIndexOf('/') 6 | const owner = repoRemovedUrl.substr(secondLastSlashIndex + 1) 7 | return { owner, repo } 8 | } 9 | -------------------------------------------------------------------------------- /lib/utils/filterUserComments.js: -------------------------------------------------------------------------------- 1 | module.exports = (comments, username) => { 2 | const userComments = comments.filter(comment => comment.user.login === username) 3 | return userComments 4 | } 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "background-finder", 3 | "version": "1.0.0", 4 | "description": "", 5 | "author": "Aditya Agarwal (adi.surge.sh)", 6 | "license": "ISC", 7 | "repository": "github:probot/background-check", 8 | "scripts": { 9 | "dev": "nodemon --exec \"npm start\"", 10 | "start": "probot run ./index.js", 11 | "probot": "probot", 12 | "simulate": "sh ./scripts/simulate.sh", 13 | "simulate:watch": "sh ./scripts/simulate-watch.sh", 14 | "sandbox": "probot simulate sandbox test/fixtures/sandbox.json ./test/sandboxes/sandbox-runner.js", 15 | "lint": "standard --verbose --fix | snazzy", 16 | "test": "jest", 17 | "test:watch": "jest --watch", 18 | "coverage": "jest --coverage", 19 | "docs": "documentation build lib/** -f html -o docs", 20 | "docs:serve": "documentation serve --watch lib/**", 21 | "deploy": "git push heroku master", 22 | "precommit": "lint-staged" 23 | }, 24 | "lint-staged": { 25 | "{lib,test}/**/*.js": [ 26 | "npm run lint", 27 | "npm run test -- --bail --findRelatedTests", 28 | "git add" 29 | ] 30 | }, 31 | "dependencies": { 32 | "probot": "6.2.1", 33 | "superagent": "^3.8.3" 34 | }, 35 | "devDependencies": { 36 | "documentation": "^7.1.0", 37 | "dotenv": "^5.0.1", 38 | "husky": "^0.14.3", 39 | "jest": "^21.2.1", 40 | "lint-staged": "^7.1.2", 41 | "nock": "^9.2.6", 42 | "nodemon": "^1.17.2", 43 | "smee-client": "^1.0.1", 44 | "snazzy": "^7.1.1", 45 | "standard": "^10.0.3" 46 | }, 47 | "engines": { 48 | "node": ">= 8.3.0" 49 | }, 50 | "standard": { 51 | "ignore": [ 52 | "docs", 53 | "public", 54 | "scripts", 55 | "assets" 56 | ], 57 | "env": [ 58 | "jest" 59 | ] 60 | }, 61 | "jest": { 62 | "verbose": true 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /public/wakemydyno.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itaditya/background-check/dcfbe379d1618807b80696ce25d3771cabc64537/public/wakemydyno.txt -------------------------------------------------------------------------------- /scripts/simulate-watch.sh: -------------------------------------------------------------------------------- 1 | # hello 2 | 3 | nodemon --exec "probot simulate $1 test/fixtures/$1.$2.json ./index.js" 4 | -------------------------------------------------------------------------------- /scripts/simulate.sh: -------------------------------------------------------------------------------- 1 | probot simulate $1 test/fixtures/$1.$2.json ./index.js 2 | -------------------------------------------------------------------------------- /test/__snapshots__/backgroundFinder.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`backgroundFinder is working 1`] = ` 4 | Array [ 5 | Array [ 6 | "https://api.github.com/repos/aps120797/playground", 7 | ], 8 | Array [ 9 | "https://api.github.com/repos/aps120797/playground", 10 | ], 11 | Array [ 12 | "https://api.github.com/repos/aps120797/playground", 13 | ], 14 | ] 15 | `; 16 | 17 | exports[`backgroundFinder is working 2`] = ` 18 | Array [ 19 | Array [ 20 | undefined, 21 | Object { 22 | "owner": "itaditya", 23 | "username": "itaditya", 24 | }, 25 | ], 26 | ] 27 | `; 28 | 29 | exports[`backgroundFinder is working 3`] = ` 30 | Array [ 31 | Array [ 32 | undefined, 33 | Object { 34 | "username": "itaditya", 35 | }, 36 | ], 37 | ] 38 | `; 39 | 40 | exports[`backgroundFinder is working 4`] = ` 41 | Array [ 42 | Array [ 43 | undefined, 44 | Object { 45 | "issueNum": 15, 46 | "owner": "itaditya", 47 | "repo": "private-gh-app-test-repo", 48 | }, 49 | ], 50 | Array [ 51 | undefined, 52 | Object { 53 | "issueNum": 15, 54 | "owner": "itaditya", 55 | "repo": "private-gh-app-test-repo", 56 | }, 57 | ], 58 | Array [ 59 | undefined, 60 | Object { 61 | "issueNum": 15, 62 | "owner": "itaditya", 63 | "repo": "private-gh-app-test-repo", 64 | }, 65 | ], 66 | ] 67 | `; 68 | 69 | exports[`backgroundFinder is working 5`] = ` 70 | Array [ 71 | Array [ 72 | "this project is the worst out there", 73 | ], 74 | Array [ 75 | "this project is the worst out there", 76 | ], 77 | Array [ 78 | "this project is the worst out there", 79 | ], 80 | ] 81 | `; 82 | 83 | exports[`backgroundFinder is working 6`] = ` 84 | Array [ 85 | Array [ 86 | undefined, 87 | Object { 88 | "owner": "itaditya", 89 | "toxicComments": Array [ 90 | Object { 91 | "link": "https://github.com/aps120797/playground/issues/17", 92 | "text": "this project is the worst out there", 93 | "toxicScore": 0.7, 94 | }, 95 | Object { 96 | "link": "https://github.com/aps120797/playground/issues/17", 97 | "text": "this project is the worst out there", 98 | "toxicScore": 0.7, 99 | }, 100 | Object { 101 | "link": "https://github.com/aps120797/playground/issues/17", 102 | "text": "this project is the worst out there", 103 | "toxicScore": 0.7, 104 | }, 105 | ], 106 | "username": "itaditya", 107 | }, 108 | ], 109 | ] 110 | `; 111 | -------------------------------------------------------------------------------- /test/__snapshots__/createDiscussionIssue.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`createDiscussionIssue is working 1`] = ` 4 | Array [ 5 | Array [ 6 | Object { 7 | "body": "Some comments from @itaditya have been found to be toxic. Review the following comments and discuss whether or not you would like to allow this contributor to participate in your community. 8 | 9 | 10 | 1. link2 has a toxicity rating of **0.9** : 11 | 12 | > text2 13 | 14 | 15 | 16 | 1. link1 has a toxicity rating of **0.8** : 17 | 18 | > text1 19 | 20 | ", 21 | "owner": "probot-background-check", 22 | "repo": "probot-discussions", 23 | "title": "itaditya-discussion", 24 | }, 25 | ], 26 | ] 27 | `; 28 | -------------------------------------------------------------------------------- /test/__snapshots__/createDiscussionRepo.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`createDiscussionRepo is working 1`] = ` 4 | Array [ 5 | Array [ 6 | Object { 7 | "auto_init": true, 8 | "description": "Repo to have discussions about toxic users", 9 | "name": "test-org-discussions", 10 | "org": "probot-background-check", 11 | "private": true, 12 | }, 13 | ], 14 | ] 15 | `; 16 | -------------------------------------------------------------------------------- /test/__snapshots__/discussionBoardSetup.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`discussionBoardSetup is working 1`] = ` 4 | Array [ 5 | Array [ 6 | undefined, 7 | Object { 8 | "appInstallerName": "itaditya", 9 | }, 10 | ], 11 | ] 12 | `; 13 | 14 | exports[`discussionBoardSetup is working 2`] = ` 15 | Array [ 16 | Array [ 17 | undefined, 18 | Object { 19 | "appInstallerName": "itaditya", 20 | "username": "itaditya", 21 | }, 22 | ], 23 | ] 24 | `; 25 | -------------------------------------------------------------------------------- /test/__snapshots__/getUserCommentedIssues.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`getUserCommentedIssues is working 1`] = ` 4 | Array [ 5 | Array [ 6 | Object { 7 | "q": "commenter:itaditya", 8 | }, 9 | ], 10 | ] 11 | `; 12 | -------------------------------------------------------------------------------- /test/__snapshots__/getUserDiscussionIssue.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`getUserDiscussionIssue is working 1`] = ` 4 | Array [ 5 | Array [ 6 | Object { 7 | "q": "repo:probot-background-check/itaditya-discussions is:issue is:open in:title itaditya-discussion", 8 | }, 9 | ], 10 | ] 11 | `; 12 | -------------------------------------------------------------------------------- /test/analyseSentiment.test.js: -------------------------------------------------------------------------------- 1 | const nock = require('nock') 2 | const request = require('superagent') 3 | require('dotenv').config() 4 | 5 | const analyseSentiment = require('../lib/utils/analyseSentiment') 6 | 7 | const { PERSPECTIVE_API_KEY } = process.env 8 | const sentimentAnalyserInstance = analyseSentiment(PERSPECTIVE_API_KEY, { 9 | dependencies: { request } 10 | }) 11 | 12 | const TOXIC_MIN_VALUE = 0.6 13 | const ERROR_FLAG = -1 14 | 15 | describe('that analyseSentiment is working', () => { 16 | test.skip('that simple toxic text is detected', async() => { 17 | const text = "@itaditya I don't like the way you do things, your library is a joke" 18 | const toxicScore = await sentimentAnalyserInstance(text) 19 | expect(toxicScore).toBeGreaterThanOrEqual(TOXIC_MIN_VALUE) 20 | }) 21 | describe('that request errors are handled properly', () => { 22 | test('that promise rejection is handled properly', async() => { 23 | const text = "@itaditya I don't know if you are right on this" 24 | const faultyRequest = { 25 | post: function () { return this }, 26 | set: function () { return this }, 27 | send: () => { 28 | return Promise.reject(new Error('error')) 29 | } 30 | } 31 | const fakeSentimentAnalyserInstance = analyseSentiment(PERSPECTIVE_API_KEY, { 32 | dependencies: { request: faultyRequest } 33 | }) 34 | const toxicScore = await fakeSentimentAnalyserInstance(text) 35 | expect(toxicScore).toBe(ERROR_FLAG) 36 | }) 37 | test('that throw is handled properly', async() => { 38 | const text = "@itaditya I don't know if you are right on this" 39 | const faultyRequest = { 40 | post: function () { return this }, 41 | set: function () { return this }, 42 | send: () => { 43 | throw (new Error('error')) 44 | } 45 | } 46 | const fakeSentimentAnalyserInstance = analyseSentiment(PERSPECTIVE_API_KEY, { 47 | dependencies: { request: faultyRequest } 48 | }) 49 | const toxicScore = await fakeSentimentAnalyserInstance(text) 50 | expect(toxicScore).toBe(ERROR_FLAG) 51 | }) 52 | }) 53 | describe('that errors not related to request are caught using nock', () => { 54 | const expectedToxicScore = 0.7 55 | beforeEach(() => { 56 | nock('https://commentanalyzer.googleapis.com/v1alpha1') 57 | .post('/comments:analyze') 58 | .query({ 59 | key: PERSPECTIVE_API_KEY 60 | }) 61 | .reply(200, { 62 | attributeScores: { 63 | TOXICITY: { 64 | summaryScore: { 65 | value: expectedToxicScore 66 | } 67 | } 68 | } 69 | }) 70 | }) 71 | afterEach(() => { 72 | nock.restore() 73 | }) 74 | test(`returns toxicScore ${expectedToxicScore}`, async() => { 75 | const text = "@itaditya I don't like the way you do things, your library is a joke" 76 | const toxicScore = await sentimentAnalyserInstance(text) 77 | expect(toxicScore).toBe(expectedToxicScore) 78 | }) 79 | test(`that undefined argument returns ${ERROR_FLAG}`, async() => { 80 | const toxicScore = await sentimentAnalyserInstance() 81 | expect(toxicScore).toBe(ERROR_FLAG) 82 | }) 83 | test(`that empty text returns ${ERROR_FLAG}`, async() => { 84 | const text = '' 85 | const toxicScore = await sentimentAnalyserInstance(text) 86 | expect(toxicScore).toBe(ERROR_FLAG) 87 | }) 88 | test(`that text of size more than 3000B returns ${ERROR_FLAG}`, async() => { 89 | let text = 'are you mad'.repeat(1000) 90 | const toxicScore = await sentimentAnalyserInstance(text) 91 | expect(toxicScore).toBe(ERROR_FLAG) 92 | }) 93 | test('that non toxic text is not considered toxic', async() => { 94 | const text = "@itaditya I don't know if you are right on this" 95 | const toxicScore = await sentimentAnalyserInstance(text) 96 | expect(toxicScore).toBeLessThanOrEqual(TOXIC_MIN_VALUE) 97 | }) 98 | }) 99 | }) 100 | -------------------------------------------------------------------------------- /test/backgroundFinder.test.js: -------------------------------------------------------------------------------- 1 | const backgroundFinder = require('../lib/backgroundFinder') 2 | 3 | /* -- Mocks -- */ 4 | const extractRepoDetails = jest.fn().mockReturnValue({ owner: 'itaditya', repo: 'private-gh-app-test-repo' }) 5 | const getUserDiscussionIssue = jest.fn().mockReturnValue({ 6 | data: { 7 | total_count: 0 8 | } 9 | }) 10 | const getUserCommentedIssues = jest.fn().mockReturnValue({ 11 | data: { 12 | total_count: 3, 13 | items: [{ 14 | number: 15, 15 | repository_url: 'https://api.github.com/repos/aps120797/playground', 16 | url: 'https://api.github.com/repos/aps120797/playground/issues/17', 17 | html_url: 'https://github.com/aps120797/playground/issues/17' 18 | }, { 19 | number: 15, 20 | repository_url: 'https://api.github.com/repos/aps120797/playground', 21 | url: 'https://api.github.com/repos/aps120797/playground/issues/17', 22 | html_url: 'https://github.com/aps120797/playground/issues/17' 23 | }, { 24 | number: 15, 25 | repository_url: 'https://api.github.com/repos/aps120797/playground', 26 | url: 'https://api.github.com/repos/aps120797/playground/issues/17', 27 | html_url: 'https://github.com/aps120797/playground/issues/17' 28 | }] 29 | } 30 | }) 31 | const getCommentsOnIssue = jest.fn().mockReturnValue({ 32 | data: [{ 33 | body: 'this project is the worst out there', 34 | user: { 35 | type: 'User', 36 | login: 'itaditya' 37 | } 38 | }] 39 | }) 40 | const sentimentAnalyser = jest.fn().mockReturnValue(0.7) 41 | const createDiscussionIssue = jest.fn().mockReturnValue(Promise.resolve({ 42 | status: 200, 43 | data: { 44 | html_url: 'https://github.com/itaditya/maintainers-discussion/issues/17' 45 | } 46 | })) 47 | /* ^- Mocks -^ */ 48 | 49 | const backgroundFinderInstance = backgroundFinder({ 50 | dependencies: { 51 | extractRepoDetails, 52 | getUserDiscussionIssue, 53 | getUserCommentedIssues, 54 | getCommentsOnIssue, 55 | sentimentAnalyser, 56 | createDiscussionIssue 57 | } 58 | }) 59 | 60 | test('backgroundFinder is working', async () => { 61 | const context = { 62 | payload: { 63 | repository: { owner: { login: 'itaditya' } }, 64 | comment: { user: { login: 'itaditya' } } 65 | }, 66 | log: console.log 67 | } 68 | await backgroundFinderInstance(context) 69 | expect(extractRepoDetails.mock.calls).toMatchSnapshot() 70 | expect(getUserDiscussionIssue.mock.calls).toMatchSnapshot() 71 | expect(getUserCommentedIssues.mock.calls).toMatchSnapshot() 72 | expect(getCommentsOnIssue.mock.calls).toMatchSnapshot() 73 | expect(sentimentAnalyser.mock.calls).toMatchSnapshot() 74 | expect(createDiscussionIssue.mock.calls).toMatchSnapshot() 75 | }) 76 | -------------------------------------------------------------------------------- /test/createDiscussionIssue.test.js: -------------------------------------------------------------------------------- 1 | const createDiscussionIssue = require('../lib/github-api/createDiscussionIssue') 2 | 3 | process.env.APP_ORG_NAME = 'probot-background-check' 4 | 5 | test('createDiscussionIssue is working', async () => { 6 | const github = { 7 | issues: { create: jest.fn() } 8 | } 9 | 10 | await createDiscussionIssue(github, { 11 | owner: 'probot', 12 | username: 'itaditya', 13 | toxicComments: [{ 14 | link: 'link1', 15 | text: 'text1', 16 | toxicScore: 0.8 17 | }, { 18 | link: 'link2', 19 | text: 'text2', 20 | toxicScore: 0.9 21 | }] 22 | }) 23 | 24 | expect(github.issues.create.mock.calls).toMatchSnapshot() 25 | }) 26 | -------------------------------------------------------------------------------- /test/createDiscussionRepo.test.js: -------------------------------------------------------------------------------- 1 | const createDiscussionRepo = require('../lib/github-api/createDiscussionRepo') 2 | 3 | process.env.APP_ORG_NAME = 'probot-background-check' 4 | 5 | test('createDiscussionRepo is working', async () => { 6 | const github = { 7 | repos: { createForOrg: jest.fn() } 8 | } 9 | 10 | // Call your function, which internally calls your above mock function 11 | await createDiscussionRepo(github, { appInstallerName: 'test-org' }) 12 | 13 | // Test that your mock function has been called 14 | expect(github.repos.createForOrg).toHaveBeenCalledWith({ 15 | org: 'probot-background-check', 16 | name: 'test-org-discussions', 17 | description: 'Repo to have discussions about toxic users', 18 | private: true, 19 | auto_init: true 20 | }) 21 | 22 | // Test that your mock function has been called with the right arguments 23 | expect(github.repos.createForOrg.mock.calls).toMatchSnapshot() 24 | }) 25 | -------------------------------------------------------------------------------- /test/discussionBoardSetup.test.js: -------------------------------------------------------------------------------- 1 | const discussionBoardSetup = require('../lib/discussionBoardSetup') 2 | 3 | /* -- Mocks -- */ 4 | const createDiscussionRepo = jest.fn() 5 | const addCollaboratorToRepo = jest.fn() 6 | /* ^- Mocks -^ */ 7 | 8 | const discussionBoardSetupInstance = discussionBoardSetup({ 9 | dependencies: { 10 | createDiscussionRepo, 11 | addCollaboratorToRepo 12 | } 13 | }) 14 | 15 | test('discussionBoardSetup is working', async () => { 16 | const context = { 17 | payload: { 18 | installation: { account: { login: 'itaditya' } }, 19 | sender: { login: 'itaditya' } 20 | }, 21 | log: console.log 22 | } 23 | await discussionBoardSetupInstance(context) 24 | expect(createDiscussionRepo.mock.calls).toMatchSnapshot() 25 | expect(addCollaboratorToRepo.mock.calls).toMatchSnapshot() 26 | }) 27 | -------------------------------------------------------------------------------- /test/fixtures/installation.created.json: -------------------------------------------------------------------------------- 1 | { 2 | "action": "created", 3 | "installation": { 4 | "id": 232862, 5 | "account": { 6 | "login": "probot-test-2-org", 7 | "id": 40889290, 8 | "node_id": "MDEyOk9yZ2FuaXphdGlvbjQwODg5Mjkw", 9 | "avatar_url": "https://avatars1.githubusercontent.com/u/40889290?v=4", 10 | "gravatar_id": "", 11 | "url": "https://api.github.com/users/probot-test-2-org", 12 | "html_url": "https://github.com/probot-test-2-org", 13 | "followers_url": "https://api.github.com/users/probot-test-2-org/followers", 14 | "following_url": "https://api.github.com/users/probot-test-2-org/following{/other_user}", 15 | "gists_url": "https://api.github.com/users/probot-test-2-org/gists{/gist_id}", 16 | "starred_url": "https://api.github.com/users/probot-test-2-org/starred{/owner}{/repo}", 17 | "subscriptions_url": "https://api.github.com/users/probot-test-2-org/subscriptions", 18 | "organizations_url": "https://api.github.com/users/probot-test-2-org/orgs", 19 | "repos_url": "https://api.github.com/users/probot-test-2-org/repos", 20 | "events_url": "https://api.github.com/users/probot-test-2-org/events{/privacy}", 21 | "received_events_url": "https://api.github.com/users/probot-test-2-org/received_events", 22 | "type": "Organization", 23 | "site_admin": false 24 | }, 25 | "repository_selection": "selected", 26 | "access_tokens_url": "https://api.github.com/installations/232862/access_tokens", 27 | "repositories_url": "https://api.github.com/installation/repositories", 28 | "html_url": "https://github.com/organizations/probot-test-2-org/settings/installations/232862", 29 | "app_id": 11546, 30 | "target_id": 40889290, 31 | "target_type": "Organization", 32 | "permissions": { 33 | "members": "write", 34 | "pull_requests": "write", 35 | "team_discussions": "write", 36 | "issues": "write", 37 | "administration": "write", 38 | "metadata": "read", 39 | "contents": "read" 40 | }, 41 | "events": [ 42 | "issues", 43 | "issue_comment", 44 | "label", 45 | "member", 46 | "organization", 47 | "pull_request", 48 | "repository", 49 | "team", 50 | "team_add", 51 | "watch" 52 | ], 53 | "created_at": 1530874729, 54 | "updated_at": 1530874729, 55 | "single_file_name": null 56 | }, 57 | "repositories": [ 58 | { 59 | "id": 139973351, 60 | "name": "playground", 61 | "full_name": "probot-test-2-org/playground", 62 | "private": false 63 | } 64 | ], 65 | "sender": { 66 | "login": "itaditya", 67 | "id": 15871340, 68 | "node_id": "MDQ6VXNlcjE1ODcxMzQw", 69 | "avatar_url": "https://avatars1.githubusercontent.com/u/15871340?v=4", 70 | "gravatar_id": "", 71 | "url": "https://api.github.com/users/itaditya", 72 | "html_url": "https://github.com/itaditya", 73 | "followers_url": "https://api.github.com/users/itaditya/followers", 74 | "following_url": "https://api.github.com/users/itaditya/following{/other_user}", 75 | "gists_url": "https://api.github.com/users/itaditya/gists{/gist_id}", 76 | "starred_url": "https://api.github.com/users/itaditya/starred{/owner}{/repo}", 77 | "subscriptions_url": "https://api.github.com/users/itaditya/subscriptions", 78 | "organizations_url": "https://api.github.com/users/itaditya/orgs", 79 | "repos_url": "https://api.github.com/users/itaditya/repos", 80 | "events_url": "https://api.github.com/users/itaditya/events{/privacy}", 81 | "received_events_url": "https://api.github.com/users/itaditya/received_events", 82 | "type": "User", 83 | "site_admin": false 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /test/fixtures/issue_comment.created.json: -------------------------------------------------------------------------------- 1 | { 2 | "action": "created", 3 | "issue": { 4 | "url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/issues/1", 5 | "repository_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo", 6 | "labels_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/issues/1/labels{/name}", 7 | "comments_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/issues/1/comments", 8 | "events_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/issues/1/events", 9 | "html_url": "https://github.com/itaditya/private-gh-app-test-repo/issues/1", 10 | "id": 324661157, 11 | "number": 1, 12 | "title": "test issue", 13 | "user": { 14 | "login": "itaditya", 15 | "id": 15871340, 16 | "avatar_url": "https://avatars1.githubusercontent.com/u/15871340?v=4", 17 | "gravatar_id": "", 18 | "url": "https://api.github.com/users/itaditya", 19 | "html_url": "https://github.com/itaditya", 20 | "followers_url": "https://api.github.com/users/itaditya/followers", 21 | "following_url": "https://api.github.com/users/itaditya/following{/other_user}", 22 | "gists_url": "https://api.github.com/users/itaditya/gists{/gist_id}", 23 | "starred_url": "https://api.github.com/users/itaditya/starred{/owner}{/repo}", 24 | "subscriptions_url": "https://api.github.com/users/itaditya/subscriptions", 25 | "organizations_url": "https://api.github.com/users/itaditya/orgs", 26 | "repos_url": "https://api.github.com/users/itaditya/repos", 27 | "events_url": "https://api.github.com/users/itaditya/events{/privacy}", 28 | "received_events_url": "https://api.github.com/users/itaditya/received_events", 29 | "type": "User", 30 | "site_admin": false 31 | }, 32 | "labels": [ 33 | 34 | ], 35 | "state": "open", 36 | "locked": false, 37 | "assignee": null, 38 | "assignees": [ 39 | 40 | ], 41 | "milestone": null, 42 | "comments": 0, 43 | "created_at": "2018-05-19T21:17:42Z", 44 | "updated_at": "2018-05-19T21:18:00Z", 45 | "closed_at": null, 46 | "author_association": "OWNER", 47 | "body": "yeah" 48 | }, 49 | "comment": { 50 | "url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/issues/comments/390433336", 51 | "html_url": "https://github.com/itaditya/private-gh-app-test-repo/issues/1#issuecomment-390433336", 52 | "issue_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/issues/1", 53 | "id": 390433336, 54 | "user": { 55 | "login": "itaditya", 56 | "id": 15871340, 57 | "avatar_url": "https://avatars1.githubusercontent.com/u/15871340?v=4", 58 | "gravatar_id": "", 59 | "url": "https://api.github.com/users/itaditya", 60 | "html_url": "https://github.com/itaditya", 61 | "followers_url": "https://api.github.com/users/itaditya/followers", 62 | "following_url": "https://api.github.com/users/itaditya/following{/other_user}", 63 | "gists_url": "https://api.github.com/users/itaditya/gists{/gist_id}", 64 | "starred_url": "https://api.github.com/users/itaditya/starred{/owner}{/repo}", 65 | "subscriptions_url": "https://api.github.com/users/itaditya/subscriptions", 66 | "organizations_url": "https://api.github.com/users/itaditya/orgs", 67 | "repos_url": "https://api.github.com/users/itaditya/repos", 68 | "events_url": "https://api.github.com/users/itaditya/events{/privacy}", 69 | "received_events_url": "https://api.github.com/users/itaditya/received_events", 70 | "type": "User", 71 | "site_admin": false 72 | }, 73 | "created_at": "2018-05-19T21:18:00Z", 74 | "updated_at": "2018-05-19T21:18:00Z", 75 | "author_association": "OWNER", 76 | "body": "hell\r\n" 77 | }, 78 | "repository": { 79 | "id": 131282717, 80 | "name": "private-gh-app-test-repo", 81 | "full_name": "itaditya/private-gh-app-test-repo", 82 | "owner": { 83 | "login": "itaditya", 84 | "id": 15871340, 85 | "avatar_url": "https://avatars1.githubusercontent.com/u/15871340?v=4", 86 | "gravatar_id": "", 87 | "url": "https://api.github.com/users/itaditya", 88 | "html_url": "https://github.com/itaditya", 89 | "followers_url": "https://api.github.com/users/itaditya/followers", 90 | "following_url": "https://api.github.com/users/itaditya/following{/other_user}", 91 | "gists_url": "https://api.github.com/users/itaditya/gists{/gist_id}", 92 | "starred_url": "https://api.github.com/users/itaditya/starred{/owner}{/repo}", 93 | "subscriptions_url": "https://api.github.com/users/itaditya/subscriptions", 94 | "organizations_url": "https://api.github.com/users/itaditya/orgs", 95 | "repos_url": "https://api.github.com/users/itaditya/repos", 96 | "events_url": "https://api.github.com/users/itaditya/events{/privacy}", 97 | "received_events_url": "https://api.github.com/users/itaditya/received_events", 98 | "type": "User", 99 | "site_admin": false 100 | }, 101 | "private": true, 102 | "html_url": "https://github.com/itaditya/private-gh-app-test-repo", 103 | "description": "To test github apps on private repo", 104 | "fork": false, 105 | "url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo", 106 | "forks_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/forks", 107 | "keys_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/keys{/key_id}", 108 | "collaborators_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/collaborators{/collaborator}", 109 | "teams_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/teams", 110 | "hooks_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/hooks", 111 | "issue_events_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/issues/events{/number}", 112 | "events_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/events", 113 | "assignees_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/assignees{/user}", 114 | "branches_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/branches{/branch}", 115 | "tags_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/tags", 116 | "blobs_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/git/blobs{/sha}", 117 | "git_tags_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/git/tags{/sha}", 118 | "git_refs_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/git/refs{/sha}", 119 | "trees_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/git/trees{/sha}", 120 | "statuses_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/statuses/{sha}", 121 | "languages_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/languages", 122 | "stargazers_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/stargazers", 123 | "contributors_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/contributors", 124 | "subscribers_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/subscribers", 125 | "subscription_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/subscription", 126 | "commits_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/commits{/sha}", 127 | "git_commits_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/git/commits{/sha}", 128 | "comments_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/comments{/number}", 129 | "issue_comment_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/issues/comments{/number}", 130 | "contents_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/contents/{+path}", 131 | "compare_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/compare/{base}...{head}", 132 | "merges_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/merges", 133 | "archive_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/{archive_format}{/ref}", 134 | "downloads_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/downloads", 135 | "issues_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/issues{/number}", 136 | "pulls_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/pulls{/number}", 137 | "milestones_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/milestones{/number}", 138 | "notifications_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/notifications{?since,all,participating}", 139 | "labels_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/labels{/name}", 140 | "releases_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/releases{/id}", 141 | "deployments_url": "https://api.github.com/repos/itaditya/private-gh-app-test-repo/deployments", 142 | "created_at": "2018-04-27T10:34:08Z", 143 | "updated_at": "2018-04-27T10:35:05Z", 144 | "pushed_at": "2018-04-27T10:35:04Z", 145 | "git_url": "git://github.com/itaditya/private-gh-app-test-repo.git", 146 | "ssh_url": "git@github.com:itaditya/private-gh-app-test-repo.git", 147 | "clone_url": "https://github.com/itaditya/private-gh-app-test-repo.git", 148 | "svn_url": "https://github.com/itaditya/private-gh-app-test-repo", 149 | "homepage": null, 150 | "size": 0, 151 | "stargazers_count": 0, 152 | "watchers_count": 0, 153 | "language": null, 154 | "has_issues": true, 155 | "has_projects": true, 156 | "has_downloads": true, 157 | "has_wiki": true, 158 | "has_pages": false, 159 | "forks_count": 0, 160 | "mirror_url": null, 161 | "archived": false, 162 | "open_issues_count": 1, 163 | "license": null, 164 | "forks": 0, 165 | "open_issues": 1, 166 | "watchers": 0, 167 | "default_branch": "master" 168 | }, 169 | "sender": { 170 | "login": "itaditya", 171 | "id": 15871340, 172 | "avatar_url": "https://avatars1.githubusercontent.com/u/15871340?v=4", 173 | "gravatar_id": "", 174 | "url": "https://api.github.com/users/itaditya", 175 | "html_url": "https://github.com/itaditya", 176 | "followers_url": "https://api.github.com/users/itaditya/followers", 177 | "following_url": "https://api.github.com/users/itaditya/following{/other_user}", 178 | "gists_url": "https://api.github.com/users/itaditya/gists{/gist_id}", 179 | "starred_url": "https://api.github.com/users/itaditya/starred{/owner}{/repo}", 180 | "subscriptions_url": "https://api.github.com/users/itaditya/subscriptions", 181 | "organizations_url": "https://api.github.com/users/itaditya/orgs", 182 | "repos_url": "https://api.github.com/users/itaditya/repos", 183 | "events_url": "https://api.github.com/users/itaditya/events{/privacy}", 184 | "received_events_url": "https://api.github.com/users/itaditya/received_events", 185 | "type": "User", 186 | "site_admin": false 187 | }, 188 | "installation": { 189 | "id": 143531 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /test/fixtures/sandbox.json: -------------------------------------------------------------------------------- 1 | { 2 | "action": "sandbox", 3 | "number": 43, 4 | "comment": { 5 | "user": { 6 | "login": "itaditya" 7 | } 8 | }, 9 | "repository": { 10 | "id": 121734483, 11 | "name": "gh-app-test-repo", 12 | "full_name": "itaditya/gh-app-test-repo", 13 | "owner": { 14 | "login": "itaditya", 15 | "id": 15871340, 16 | "avatar_url": "https://avatars1.githubusercontent.com/u/15871340?v=4", 17 | "gravatar_id": "", 18 | "url": "https://api.github.com/users/itaditya", 19 | "html_url": "https://github.com/itaditya", 20 | "followers_url": "https://api.github.com/users/itaditya/followers", 21 | "following_url": "https://api.github.com/users/itaditya/following{/other_user}", 22 | "gists_url": "https://api.github.com/users/itaditya/gists{/gist_id}", 23 | "starred_url": "https://api.github.com/users/itaditya/starred{/owner}{/repo}", 24 | "subscriptions_url": "https://api.github.com/users/itaditya/subscriptions", 25 | "organizations_url": "https://api.github.com/users/itaditya/orgs", 26 | "repos_url": "https://api.github.com/users/itaditya/repos", 27 | "events_url": "https://api.github.com/users/itaditya/events{/privacy}", 28 | "received_events_url": "https://api.github.com/users/itaditya/received_events", 29 | "type": "User", 30 | "site_admin": false 31 | }, 32 | "private": false, 33 | "html_url": "https://github.com/itaditya/gh-app-test-repo", 34 | "description": null, 35 | "fork": false, 36 | "url": "https://api.github.com/repos/itaditya/gh-app-test-repo", 37 | "forks_url": "https://api.github.com/repos/itaditya/gh-app-test-repo/forks", 38 | "keys_url": "https://api.github.com/repos/itaditya/gh-app-test-repo/keys{/key_id}", 39 | "collaborators_url": "https://api.github.com/repos/itaditya/gh-app-test-repo/collaborators{/collaborator}", 40 | "teams_url": "https://api.github.com/repos/itaditya/gh-app-test-repo/teams", 41 | "hooks_url": "https://api.github.com/repos/itaditya/gh-app-test-repo/hooks", 42 | "issue_events_url": "https://api.github.com/repos/itaditya/gh-app-test-repo/issues/events{/number}", 43 | "events_url": "https://api.github.com/repos/itaditya/gh-app-test-repo/events", 44 | "assignees_url": "https://api.github.com/repos/itaditya/gh-app-test-repo/assignees{/user}", 45 | "branches_url": "https://api.github.com/repos/itaditya/gh-app-test-repo/branches{/branch}", 46 | "tags_url": "https://api.github.com/repos/itaditya/gh-app-test-repo/tags", 47 | "blobs_url": "https://api.github.com/repos/itaditya/gh-app-test-repo/git/blobs{/sha}", 48 | "git_tags_url": "https://api.github.com/repos/itaditya/gh-app-test-repo/git/tags{/sha}", 49 | "git_refs_url": "https://api.github.com/repos/itaditya/gh-app-test-repo/git/refs{/sha}", 50 | "trees_url": "https://api.github.com/repos/itaditya/gh-app-test-repo/git/trees{/sha}", 51 | "statuses_url": "https://api.github.com/repos/itaditya/gh-app-test-repo/statuses/{sha}", 52 | "languages_url": "https://api.github.com/repos/itaditya/gh-app-test-repo/languages", 53 | "stargazers_url": "https://api.github.com/repos/itaditya/gh-app-test-repo/stargazers", 54 | "contributors_url": "https://api.github.com/repos/itaditya/gh-app-test-repo/contributors", 55 | "subscribers_url": "https://api.github.com/repos/itaditya/gh-app-test-repo/subscribers", 56 | "subscription_url": "https://api.github.com/repos/itaditya/gh-app-test-repo/subscription", 57 | "commits_url": "https://api.github.com/repos/itaditya/gh-app-test-repo/commits{/sha}", 58 | "git_commits_url": "https://api.github.com/repos/itaditya/gh-app-test-repo/git/commits{/sha}", 59 | "comments_url": "https://api.github.com/repos/itaditya/gh-app-test-repo/comments{/number}", 60 | "issue_comment_url": "https://api.github.com/repos/itaditya/gh-app-test-repo/issues/comments{/number}", 61 | "contents_url": "https://api.github.com/repos/itaditya/gh-app-test-repo/contents/{+path}", 62 | "compare_url": "https://api.github.com/repos/itaditya/gh-app-test-repo/compare/{base}...{head}", 63 | "merges_url": "https://api.github.com/repos/itaditya/gh-app-test-repo/merges", 64 | "archive_url": "https://api.github.com/repos/itaditya/gh-app-test-repo/{archive_format}{/ref}", 65 | "downloads_url": "https://api.github.com/repos/itaditya/gh-app-test-repo/downloads", 66 | "issues_url": "https://api.github.com/repos/itaditya/gh-app-test-repo/issues{/number}", 67 | "pulls_url": "https://api.github.com/repos/itaditya/gh-app-test-repo/pulls{/number}", 68 | "milestones_url": "https://api.github.com/repos/itaditya/gh-app-test-repo/milestones{/number}", 69 | "notifications_url": "https://api.github.com/repos/itaditya/gh-app-test-repo/notifications{?since,all,participating}", 70 | "labels_url": "https://api.github.com/repos/itaditya/gh-app-test-repo/labels{/name}", 71 | "releases_url": "https://api.github.com/repos/itaditya/gh-app-test-repo/releases{/id}", 72 | "deployments_url": "https://api.github.com/repos/itaditya/gh-app-test-repo/deployments", 73 | "created_at": "2018-02-16T09:38:58Z", 74 | "updated_at": "2018-04-16T10:40:01Z", 75 | "pushed_at": "2018-04-18T12:44:58Z", 76 | "git_url": "git://github.com/itaditya/gh-app-test-repo.git", 77 | "ssh_url": "git@github.com:itaditya/gh-app-test-repo.git", 78 | "clone_url": "https://github.com/itaditya/gh-app-test-repo.git", 79 | "svn_url": "https://github.com/itaditya/gh-app-test-repo", 80 | "homepage": null, 81 | "size": 8, 82 | "stargazers_count": 0, 83 | "watchers_count": 0, 84 | "language": "HTML", 85 | "has_issues": true, 86 | "has_projects": true, 87 | "has_downloads": true, 88 | "has_wiki": true, 89 | "has_pages": false, 90 | "forks_count": 1, 91 | "mirror_url": null, 92 | "archived": false, 93 | "open_issues_count": 40, 94 | "license": null, 95 | "forks": 1, 96 | "open_issues": 40, 97 | "watchers": 0, 98 | "default_branch": "master" 99 | }, 100 | "sender": { 101 | "login": "bootstrap-dev[bot]", 102 | "id": 38453538, 103 | "avatar_url": "https://avatars1.githubusercontent.com/u/15871340?v=4", 104 | "gravatar_id": "", 105 | "url": "https://api.github.com/users/bootstrap-dev%5Bbot%5D", 106 | "html_url": "https://github.com/apps/bootstrap-dev", 107 | "followers_url": "https://api.github.com/users/bootstrap-dev%5Bbot%5D/followers", 108 | "following_url": "https://api.github.com/users/bootstrap-dev%5Bbot%5D/following{/other_user}", 109 | "gists_url": "https://api.github.com/users/bootstrap-dev%5Bbot%5D/gists{/gist_id}", 110 | "starred_url": "https://api.github.com/users/bootstrap-dev%5Bbot%5D/starred{/owner}{/repo}", 111 | "subscriptions_url": "https://api.github.com/users/bootstrap-dev%5Bbot%5D/subscriptions", 112 | "organizations_url": "https://api.github.com/users/bootstrap-dev%5Bbot%5D/orgs", 113 | "repos_url": "https://api.github.com/users/bootstrap-dev%5Bbot%5D/repos", 114 | "events_url": "https://api.github.com/users/bootstrap-dev%5Bbot%5D/events{/privacy}", 115 | "received_events_url": "https://api.github.com/users/bootstrap-dev%5Bbot%5D/received_events", 116 | "type": "Bot", 117 | "site_admin": false 118 | }, 119 | "installation": { 120 | "id": 143531 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /test/getUserCommentedIssues.test.js: -------------------------------------------------------------------------------- 1 | const getUserCommentedIssues = require('../lib/github-api/getUserCommentedIssues') 2 | 3 | test('getUserCommentedIssues is working', async () => { 4 | const github = { 5 | search: { issues: jest.fn() } 6 | } 7 | 8 | await getUserCommentedIssues(github, { 9 | username: 'itaditya' 10 | }) 11 | 12 | expect(github.search.issues.mock.calls).toMatchSnapshot() 13 | }) 14 | -------------------------------------------------------------------------------- /test/getUserDiscussionIssue.test.js: -------------------------------------------------------------------------------- 1 | const getUserDiscussionIssue = require('../lib/github-api/getUserDiscussionIssue') 2 | 3 | process.env.APP_ORG_NAME = 'probot-background-check' 4 | 5 | test('getUserDiscussionIssue is working', async () => { 6 | const github = { 7 | search: { issues: jest.fn() } 8 | } 9 | 10 | await getUserDiscussionIssue(github, { 11 | owner: 'itaditya', 12 | username: 'itaditya' 13 | }) 14 | 15 | expect(github.search.issues.mock.calls).toMatchSnapshot() 16 | }) 17 | -------------------------------------------------------------------------------- /test/index.test.js: -------------------------------------------------------------------------------- 1 | // You can import your modules 2 | // const index = require('../index') 3 | 4 | test('that we can run tests', () => { 5 | // your real tests go here 6 | expect(1 + 2 + 3).toBe(6) 7 | }) 8 | 9 | // For more information about testing with Jest see: 10 | // https://facebook.github.io/jest/ 11 | -------------------------------------------------------------------------------- /test/sandboxes/backgroundFinder.sandbox.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config() 2 | const request = require('superagent') 3 | 4 | const extractRepoDetails = require('../../lib/utils/extractRepoDetailsFromUrl') 5 | const analyseSentiment = require('../../lib/utils/analyseSentiment') 6 | const getUserDiscussionIssue = require('../../lib/github-api/getUserDiscussionIssue') 7 | const getUserCommentedIssues = require('../../lib/github-api/getUserCommentedIssues') 8 | const getCommentsOnIssue = require('../../lib/github-api/getCommentsOnIssue') 9 | const createDiscussionIssue = require('../../lib/github-api/createDiscussionIssue') 10 | 11 | const sentimentAnalyser = analyseSentiment(process.env.PERSPECTIVE_API_KEY, { 12 | dependencies: { request } 13 | }) 14 | 15 | const backgroundFinder = require('../../lib/backgroundFinder')({ 16 | dependencies: { 17 | extractRepoDetails, 18 | getUserDiscussionIssue, 19 | getUserCommentedIssues, 20 | getCommentsOnIssue, 21 | sentimentAnalyser, 22 | createDiscussionIssue 23 | } 24 | }) 25 | 26 | module.exports = async context => { 27 | await backgroundFinder(context) 28 | } 29 | -------------------------------------------------------------------------------- /test/sandboxes/createDiscussionIssue.sandbox.js: -------------------------------------------------------------------------------- 1 | const createDiscussionIssue = require('../../lib/github-api/createDiscussionIssue') 2 | 3 | module.exports = async context => { 4 | const toxicComments = [{ 5 | link: 'https://github.com/itaditya/gh-app-test-repo/issues/60', 6 | text: "what is the meaning of this, are you mad? Seriously how could you create such a sinister thing. I curse that your bot doesn't work", 7 | toxicScore: 0.7 8 | }, { 9 | link: 'https://github.com/itaditya/gh-app-test-repo/issues/60', 10 | text: "what is the meaning of this, are you mad? Seriously how could you create such a sinister thing. I curse that your bot doesn't work", 11 | toxicScore: 0.6 12 | }] 13 | const result = await createDiscussionIssue(context.github, { 14 | owner: 'itaditya', 15 | username: 'itaditya', 16 | toxicComments 17 | }) 18 | console.log(result) 19 | } 20 | -------------------------------------------------------------------------------- /test/sandboxes/createDiscussionRepo.sandbox.js: -------------------------------------------------------------------------------- 1 | const octokit = require('probot/lib/github')() 2 | 3 | const createDiscussionRepo = require('../../lib/github-api/createDiscussionRepo') 4 | 5 | module.exports = async context => { 6 | octokit.authenticate({ 7 | type: 'token', 8 | token: process.env.GITHUB_ACCESS_TOKEN 9 | }) 10 | await createDiscussionRepo(octokit, { 11 | appInstallerName: 'test-org' 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /test/sandboxes/discussionBoardSetup.sandbox.js: -------------------------------------------------------------------------------- 1 | const githubClient = require('probot/lib/github')() 2 | 3 | const createDiscussionRepo = require('../../lib/github-api/createDiscussionRepo') 4 | const addCollaboratorToRepo = require('../../lib/github-api/addCollaboratorToRepo') 5 | 6 | module.exports = async context => { 7 | githubClient.authenticate({ 8 | type: 'token', 9 | token: process.env.GITHUB_ACCESS_TOKEN 10 | }) 11 | const discussionBoardSetup = require('../../lib/discussionBoardSetup')({ 12 | dependencies: { 13 | createDiscussionRepo, 14 | addCollaboratorToRepo, 15 | githubClient 16 | } 17 | }) 18 | 19 | const appInstallerName = 'itaditya-' + Math.random() 20 | 21 | console.log(process.env.APP_ORG_NAME) 22 | 23 | Object.assign(context.payload, { 24 | installation: { 25 | account: { 26 | login: appInstallerName 27 | } 28 | }, 29 | sender: { 30 | login: 'bot-42' 31 | } 32 | }) 33 | await discussionBoardSetup(context) 34 | } 35 | -------------------------------------------------------------------------------- /test/sandboxes/getCommentsOnIssue.sandbox.js: -------------------------------------------------------------------------------- 1 | const getCommentsOnIssue = require('../../lib/github-api/getCommentsOnIssue') 2 | 3 | module.exports = async context => { 4 | const result = await getCommentsOnIssue(context.github, { 5 | owner: 'itaditya', 6 | repo: 'maintainers-discussion', 7 | issueNum: 2 8 | }) 9 | const { data: comments } = result 10 | console.log('First Comment: \n', comments[0]) 11 | } 12 | -------------------------------------------------------------------------------- /test/sandboxes/getPublicComments.sandbox.js: -------------------------------------------------------------------------------- 1 | const getPublicComments = require('../../lib/getPublicComments') 2 | 3 | module.exports = async context => { 4 | const comments = await getPublicComments(context.github, { 5 | username: 'itaditya' 6 | }) 7 | console.log('First Comment: \n', comments[0]) 8 | console.log('Comments Data', comments.map(comment => ({ url: comment.html_url, body: comment.body }))) 9 | } 10 | -------------------------------------------------------------------------------- /test/sandboxes/getUserCommentedIssues.sandbox.js: -------------------------------------------------------------------------------- 1 | const getUserCommentedIssues = require('../../lib/github-api/getUserCommentedIssues') 2 | 3 | module.exports = async context => { 4 | const result = await getUserCommentedIssues(context.github, { 5 | username: 'itaditya' 6 | }) 7 | const { data: { total_count, items: issues } } = result 8 | console.log('Total Issues:', total_count) 9 | console.log('Fetched Issues:', issues.length) 10 | console.log('First Issue -\n', issues[0]) 11 | } 12 | -------------------------------------------------------------------------------- /test/sandboxes/getUserDiscussionIssue.sandbox.js: -------------------------------------------------------------------------------- 1 | const getUserDiscussionIssue = require('../../lib/github-api/getUserDiscussionIssue') 2 | 3 | module.exports = async context => { 4 | const userIssueResult = await getUserDiscussionIssue(context.github, { 5 | username: 'itaditya', 6 | owner: 'itaditya' 7 | }) 8 | console.log('userIssueResult.data.total_count', userIssueResult.data.total_count) 9 | } 10 | -------------------------------------------------------------------------------- /test/sandboxes/sandbox-runner.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config({path: '../../.env'}) 2 | const numOfArgs = process.argv.length 3 | 4 | if (numOfArgs < 6) { 5 | console.log('Incorrect Usage') 6 | process.exit() 7 | } 8 | 9 | const sandboxNameArg = process.argv[numOfArgs - 1] 10 | const sandboxName = sandboxNameArg.substr(2) 11 | 12 | const sandbox = require(`./${sandboxName}.sandbox`) 13 | 14 | module.exports = robot => { 15 | robot.on('sandbox', async context => { 16 | try { 17 | await sandbox(context) 18 | } catch (err) { 19 | console.log('err', err) 20 | console.log('Error Occured') 21 | } finally { 22 | process.exit() 23 | } 24 | }) 25 | } 26 | --------------------------------------------------------------------------------