├── .github └── workflows │ ├── npm-publish.yml │ └── test_action.yml ├── .gitignore ├── .mocharc.json ├── LICENSE ├── README.md ├── action.yml ├── dist └── index.js ├── index.js ├── package-lock.json ├── package.json └── src ├── IssueUtil.js ├── Parser.js ├── Parser.test.js └── test_data ├── demo_checkbox_disabled.txt ├── demo_checkbox_enabled.txt ├── demo_different_open_close.txt ├── demo_missing_responses.txt ├── demo_same_open_close.txt ├── example_with_checkboxes.txt ├── example_with_checkboxes_2.txt ├── example_with_hidden_metadata.txt └── prem_test.txt /.github/workflows/npm-publish.yml: -------------------------------------------------------------------------------- 1 | name: Testing triggering 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | test: 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - run: echo "hello there :wave:" 12 | -------------------------------------------------------------------------------- /.github/workflows/test_action.yml: -------------------------------------------------------------------------------- 1 | name: Test Action 2 | 3 | on: 4 | issues: 5 | types: [opened, reopened] 6 | 7 | jobs: 8 | test: 9 | name: Test Action 10 | if: contains(github.event.issue.labels.*.name, 'test-action') 11 | 12 | runs-on: ubuntu-22.04 13 | 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v4 17 | 18 | - name: Run Action 19 | id: parse 20 | uses: ./ 21 | with: 22 | issue_id: ${{ github.event.issue.number }} 23 | separator: '###' 24 | label_marker_start: '>>' 25 | label_marker_end: '>>' 26 | 27 | - name: Show parsed data JSON 28 | env: 29 | parsed_data: ${{ steps.parse.outputs.payload }} 30 | run: | 31 | echo "$parsed_data" 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /.mocharc.json: -------------------------------------------------------------------------------- 1 | { 2 | "recursive": true 3 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Peter Murray 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 | # issue-forms-body-parser 2 | 3 | GitHub Action that will parse the issue body that has been generated from an Issue Form Template. 4 | 5 | The purpose of this action is to take the collected input from the user (ideally nothing overly free form to make it difficult to parse) and return the parsed results into a JSON encoded object. 6 | 7 | To achieve this, we need to define a separator and some markers for the opening/closing of the label for the value provided by the user. 8 | 9 | Currently as of writing this, the Issue form templates will use the h3 header `###` in the markdown as the separator. 10 | 11 | It is then up to the person defining the labels to use a consistent open/close marker for all the form entries being collected from the user in the Issue Template. 12 | 13 | So in this example if I was to use `>>` and `<<` characters to enclose the labels for the various inputs/fields in the template, we can later parse the generated issue body that would be created: 14 | 15 | ``` 16 | ### >>demo-repository-owner<< 17 | 18 | octodemo 19 | 20 | ### >>demo-repository-name<< 21 | 22 | pm-automation-test-001 23 | 24 | ### >>template<< 25 | 26 | octodemo/template-demo-github-user-search 27 | ``` 28 | 29 | ## Parameters 30 | 31 | |Input | Required | Description | 32 | | --------------------------| -------- | ------------------------------- | 33 | | `github_token` | `true` | PAT(Personal Access Token) for accessing the issues on the repository, defaults to `${{ github.token }}`. | 34 | | `repository` | `true` | The fully qualified repository that has the issue, defaults to `${{ github.repository }}`. | 35 | | `issue_id` | `true` | The id of the issue to load the content from.| 36 | | `separator` | `false` | The separator between the fields defaults to `###` which is markdown h3 which GitHub is currently defaulting to | 37 | | `label_marker_start` | `true` | The characters to match for the beginning of a label | 38 | | `label_marker_end` | `true` | The characters to match for the ending of a label | 39 | | `generate_summary` | `false` | Generate an actions summary with the parsed data, optional and defaults to `false` | 40 | 41 | 42 | ## Checkbox parsing 43 | If you have checkboxes rendered in the template, this action will provide them as an object of the name of the checkbox label associated with a `true` or `false` value. 44 | 45 | e.g. 46 | ``` 47 | ### >>Languages<< 48 | 49 | - [X] English 50 | - [X] French 51 | - [ ] German 52 | ``` 53 | 54 | would result in a JSON object that looks like this; 55 | 56 | ``` 57 | { 58 | "Languages": { 59 | "English": true, 60 | "French": true, 61 | "German": false 62 | } 63 | } 64 | ``` 65 | 66 | ## Usage 67 | 68 | Usage to parse the message example above: 69 | 70 | ``` 71 | steps: 72 | - name: Run Issue form parser 73 | id: parse 74 | uses: peter-murray/issue-forms-body-parser@v4.0.0 75 | with: 76 | issue_id: ${{ github.event.issue.number }} 77 | separator: '###' 78 | label_marker_start: '>>' 79 | label_marker_end: '<<' 80 | 81 | - name: Show parsed data JSON 82 | env: 83 | parsed_data: ${{ steps.parse.outputs.payload }} 84 | run: | 85 | echo "$parsed_data" 86 | ``` 87 | 88 | The JSON payload that is extracted would look like this: 89 | 90 | ```json 91 | { 92 | "demo-repository-owner":"octodemo", 93 | "demo-repository-name":"pm-automation-test-001", 94 | "template":"octodemo/template-demo-github-user-search" 95 | } 96 | ``` 97 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Issue Form Body Parser 3 | description: Parses the body of an issue that was built using an Issue form definition 4 | author: peter-murray 5 | 6 | branding: 7 | icon: alert-circle 8 | color: blue 9 | 10 | inputs: 11 | github_token: 12 | description: The GitHub token that can be used to obtain the Issue via API lookup 13 | default: ${{ github.token }} 14 | required: true 15 | 16 | repository: 17 | description: The repository that holds the issue, in the form of 'owner/repo' 18 | default: ${{ github.repository }} 19 | required: true 20 | 21 | issue_id: 22 | description: The id of the issue to use to extract a payload from the body 23 | required: true 24 | 25 | separator: 26 | description: The separator for the form sections in the issue 27 | required: true 28 | default: '###' 29 | 30 | label_marker_start: 31 | description: The string that is used to identify the start of the form label field 32 | required: true 33 | default: ">>" 34 | 35 | label_marker_end: 36 | description: The string that is used to identify the end of the form label field 37 | required: true 38 | default: "<<" 39 | 40 | generate_summary: 41 | description: If true, will generate a summary of the form data in the payload 42 | required: false 43 | default: false 44 | 45 | outputs: 46 | payload: 47 | description: The extracted payload data from the issue body labels in JSON encoded form 48 | 49 | runs: 50 | using: node20 51 | main: dist/index.js -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const core = require('@actions/core') 2 | , IssueUtil = require('./src/IssueUtil') 3 | , Parser = require('./src/Parser') 4 | ; 5 | 6 | function getRequiredInputValue(key) { 7 | return core.getInput(key, { required: true }); 8 | } 9 | 10 | async function run() { 11 | try { 12 | const issueId = getRequiredInputValue('issue_id') 13 | , githubToken = getRequiredInputValue('github_token') 14 | , parserSeparator = getRequiredInputValue('separator') 15 | , parserMarkerStart = getRequiredInputValue('label_marker_start') 16 | , parserMarkerEnd = getRequiredInputValue('label_marker_end') 17 | , repository = getRequiredInputValue('repository') 18 | , generateSummary = core.getBooleanInput('generate_summary') 19 | ; 20 | 21 | const issueUtil = new IssueUtil(githubToken) 22 | , parser = new Parser(parserSeparator, parserMarkerStart, parserMarkerEnd) 23 | ; 24 | 25 | const issueBody = await issueUtil.getIssueBody(repository, issueId); 26 | 27 | const parsed = parser.parse(issueBody); 28 | if (parsed !== undefined) { 29 | core.setOutput('payload', parsed); 30 | 31 | if (generateSummary) { 32 | core.summary.addHeading(`Issue payload`, 3); 33 | core.summary.addCodeBlock(JSON.stringify(parsed, null, 2)); 34 | core.summary.write(); 35 | } 36 | } else { 37 | core.setFailed(`There was no valid payload found in the issue: ${issueId}.`); 38 | } 39 | } catch (err) { 40 | core.setFailed(err); 41 | } 42 | } 43 | 44 | run(); 45 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "issue-body-parser", 3 | "version": "4.2.1", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "issue-body-parser", 9 | "version": "4.2.1", 10 | "license": "MIT", 11 | "dependencies": { 12 | "@actions/core": "^1.10.1", 13 | "@actions/github": "^6.0.0" 14 | }, 15 | "devDependencies": { 16 | "@vercel/ncc": "^0.38.1", 17 | "chai": "^4.3.6", 18 | "mocha": "^10.0.0" 19 | } 20 | }, 21 | "node_modules/@actions/core": { 22 | "version": "1.10.1", 23 | "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.1.tgz", 24 | "integrity": "sha512-3lBR9EDAY+iYIpTnTIXmWcNbX3T2kCkAEQGIQx4NVQ0575nk2k3GRZDTPQG+vVtS2izSLmINlxXf0uLtnrTP+g==", 25 | "dependencies": { 26 | "@actions/http-client": "^2.0.1", 27 | "uuid": "^8.3.2" 28 | } 29 | }, 30 | "node_modules/@actions/github": { 31 | "version": "6.0.0", 32 | "resolved": "https://registry.npmjs.org/@actions/github/-/github-6.0.0.tgz", 33 | "integrity": "sha512-alScpSVnYmjNEXboZjarjukQEzgCRmjMv6Xj47fsdnqGS73bjJNDpiiXmp8jr0UZLdUB6d9jW63IcmddUP+l0g==", 34 | "dependencies": { 35 | "@actions/http-client": "^2.2.0", 36 | "@octokit/core": "^5.0.1", 37 | "@octokit/plugin-paginate-rest": "^9.0.0", 38 | "@octokit/plugin-rest-endpoint-methods": "^10.0.0" 39 | } 40 | }, 41 | "node_modules/@actions/http-client": { 42 | "version": "2.2.0", 43 | "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.0.tgz", 44 | "integrity": "sha512-q+epW0trjVUUHboliPb4UF9g2msf+w61b32tAkFEwL/IwP0DQWgbCMM0Hbe3e3WXSKz5VcUXbzJQgy8Hkra/Lg==", 45 | "dependencies": { 46 | "tunnel": "^0.0.6", 47 | "undici": "^5.25.4" 48 | } 49 | }, 50 | "node_modules/@fastify/busboy": { 51 | "version": "2.1.0", 52 | "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.0.tgz", 53 | "integrity": "sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==", 54 | "engines": { 55 | "node": ">=14" 56 | } 57 | }, 58 | "node_modules/@octokit/auth-token": { 59 | "version": "4.0.0", 60 | "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz", 61 | "integrity": "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==", 62 | "engines": { 63 | "node": ">= 18" 64 | } 65 | }, 66 | "node_modules/@octokit/core": { 67 | "version": "5.0.2", 68 | "resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.0.2.tgz", 69 | "integrity": "sha512-cZUy1gUvd4vttMic7C0lwPed8IYXWYp8kHIMatyhY8t8n3Cpw2ILczkV5pGMPqef7v0bLo0pOHrEHarsau2Ydg==", 70 | "dependencies": { 71 | "@octokit/auth-token": "^4.0.0", 72 | "@octokit/graphql": "^7.0.0", 73 | "@octokit/request": "^8.0.2", 74 | "@octokit/request-error": "^5.0.0", 75 | "@octokit/types": "^12.0.0", 76 | "before-after-hook": "^2.2.0", 77 | "universal-user-agent": "^6.0.0" 78 | }, 79 | "engines": { 80 | "node": ">= 18" 81 | } 82 | }, 83 | "node_modules/@octokit/endpoint": { 84 | "version": "9.0.4", 85 | "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.4.tgz", 86 | "integrity": "sha512-DWPLtr1Kz3tv8L0UvXTDP1fNwM0S+z6EJpRcvH66orY6Eld4XBMCSYsaWp4xIm61jTWxK68BrR7ibO+vSDnZqw==", 87 | "dependencies": { 88 | "@octokit/types": "^12.0.0", 89 | "universal-user-agent": "^6.0.0" 90 | }, 91 | "engines": { 92 | "node": ">= 18" 93 | } 94 | }, 95 | "node_modules/@octokit/graphql": { 96 | "version": "7.0.2", 97 | "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.0.2.tgz", 98 | "integrity": "sha512-OJ2iGMtj5Tg3s6RaXH22cJcxXRi7Y3EBqbHTBRq+PQAqfaS8f/236fUrWhfSn8P4jovyzqucxme7/vWSSZBX2Q==", 99 | "dependencies": { 100 | "@octokit/request": "^8.0.1", 101 | "@octokit/types": "^12.0.0", 102 | "universal-user-agent": "^6.0.0" 103 | }, 104 | "engines": { 105 | "node": ">= 18" 106 | } 107 | }, 108 | "node_modules/@octokit/openapi-types": { 109 | "version": "19.1.0", 110 | "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-19.1.0.tgz", 111 | "integrity": "sha512-6G+ywGClliGQwRsjvqVYpklIfa7oRPA0vyhPQG/1Feh+B+wU0vGH1JiJ5T25d3g1JZYBHzR2qefLi9x8Gt+cpw==" 112 | }, 113 | "node_modules/@octokit/plugin-paginate-rest": { 114 | "version": "9.1.5", 115 | "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.1.5.tgz", 116 | "integrity": "sha512-WKTQXxK+bu49qzwv4qKbMMRXej1DU2gq017euWyKVudA6MldaSSQuxtz+vGbhxV4CjxpUxjZu6rM2wfc1FiWVg==", 117 | "dependencies": { 118 | "@octokit/types": "^12.4.0" 119 | }, 120 | "engines": { 121 | "node": ">= 18" 122 | }, 123 | "peerDependencies": { 124 | "@octokit/core": ">=5" 125 | } 126 | }, 127 | "node_modules/@octokit/plugin-rest-endpoint-methods": { 128 | "version": "10.2.0", 129 | "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-10.2.0.tgz", 130 | "integrity": "sha512-ePbgBMYtGoRNXDyKGvr9cyHjQ163PbwD0y1MkDJCpkO2YH4OeXX40c4wYHKikHGZcpGPbcRLuy0unPUuafco8Q==", 131 | "dependencies": { 132 | "@octokit/types": "^12.3.0" 133 | }, 134 | "engines": { 135 | "node": ">= 18" 136 | }, 137 | "peerDependencies": { 138 | "@octokit/core": ">=5" 139 | } 140 | }, 141 | "node_modules/@octokit/request": { 142 | "version": "8.1.6", 143 | "resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.1.6.tgz", 144 | "integrity": "sha512-YhPaGml3ncZC1NfXpP3WZ7iliL1ap6tLkAp6MvbK2fTTPytzVUyUesBBogcdMm86uRYO5rHaM1xIWxigWZ17MQ==", 145 | "dependencies": { 146 | "@octokit/endpoint": "^9.0.0", 147 | "@octokit/request-error": "^5.0.0", 148 | "@octokit/types": "^12.0.0", 149 | "universal-user-agent": "^6.0.0" 150 | }, 151 | "engines": { 152 | "node": ">= 18" 153 | } 154 | }, 155 | "node_modules/@octokit/request-error": { 156 | "version": "5.0.1", 157 | "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-5.0.1.tgz", 158 | "integrity": "sha512-X7pnyTMV7MgtGmiXBwmO6M5kIPrntOXdyKZLigNfQWSEQzVxR4a4vo49vJjTWX70mPndj8KhfT4Dx+2Ng3vnBQ==", 159 | "dependencies": { 160 | "@octokit/types": "^12.0.0", 161 | "deprecation": "^2.0.0", 162 | "once": "^1.4.0" 163 | }, 164 | "engines": { 165 | "node": ">= 18" 166 | } 167 | }, 168 | "node_modules/@octokit/types": { 169 | "version": "12.4.0", 170 | "resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.4.0.tgz", 171 | "integrity": "sha512-FLWs/AvZllw/AGVs+nJ+ELCDZZJk+kY0zMen118xhL2zD0s1etIUHm1odgjP7epxYU1ln7SZxEUWYop5bhsdgQ==", 172 | "dependencies": { 173 | "@octokit/openapi-types": "^19.1.0" 174 | } 175 | }, 176 | "node_modules/@vercel/ncc": { 177 | "version": "0.38.1", 178 | "resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.38.1.tgz", 179 | "integrity": "sha512-IBBb+iI2NLu4VQn3Vwldyi2QwaXt5+hTyh58ggAMoCGE6DJmPvwL3KPBWcJl1m9LYPChBLE980Jw+CS4Wokqxw==", 180 | "dev": true, 181 | "bin": { 182 | "ncc": "dist/ncc/cli.js" 183 | } 184 | }, 185 | "node_modules/ansi-colors": { 186 | "version": "4.1.1", 187 | "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", 188 | "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", 189 | "dev": true, 190 | "engines": { 191 | "node": ">=6" 192 | } 193 | }, 194 | "node_modules/ansi-regex": { 195 | "version": "5.0.1", 196 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 197 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 198 | "dev": true, 199 | "engines": { 200 | "node": ">=8" 201 | } 202 | }, 203 | "node_modules/ansi-styles": { 204 | "version": "4.3.0", 205 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 206 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 207 | "dev": true, 208 | "dependencies": { 209 | "color-convert": "^2.0.1" 210 | }, 211 | "engines": { 212 | "node": ">=8" 213 | }, 214 | "funding": { 215 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 216 | } 217 | }, 218 | "node_modules/anymatch": { 219 | "version": "3.1.3", 220 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", 221 | "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", 222 | "dev": true, 223 | "dependencies": { 224 | "normalize-path": "^3.0.0", 225 | "picomatch": "^2.0.4" 226 | }, 227 | "engines": { 228 | "node": ">= 8" 229 | } 230 | }, 231 | "node_modules/argparse": { 232 | "version": "2.0.1", 233 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", 234 | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", 235 | "dev": true 236 | }, 237 | "node_modules/assertion-error": { 238 | "version": "1.1.0", 239 | "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", 240 | "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", 241 | "dev": true, 242 | "engines": { 243 | "node": "*" 244 | } 245 | }, 246 | "node_modules/balanced-match": { 247 | "version": "1.0.2", 248 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 249 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 250 | "dev": true 251 | }, 252 | "node_modules/before-after-hook": { 253 | "version": "2.2.3", 254 | "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", 255 | "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==" 256 | }, 257 | "node_modules/binary-extensions": { 258 | "version": "2.2.0", 259 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", 260 | "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", 261 | "dev": true, 262 | "engines": { 263 | "node": ">=8" 264 | } 265 | }, 266 | "node_modules/brace-expansion": { 267 | "version": "2.0.1", 268 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", 269 | "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", 270 | "dev": true, 271 | "dependencies": { 272 | "balanced-match": "^1.0.0" 273 | } 274 | }, 275 | "node_modules/braces": { 276 | "version": "3.0.2", 277 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 278 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 279 | "dev": true, 280 | "dependencies": { 281 | "fill-range": "^7.0.1" 282 | }, 283 | "engines": { 284 | "node": ">=8" 285 | } 286 | }, 287 | "node_modules/browser-stdout": { 288 | "version": "1.3.1", 289 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", 290 | "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", 291 | "dev": true 292 | }, 293 | "node_modules/camelcase": { 294 | "version": "6.3.0", 295 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", 296 | "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", 297 | "dev": true, 298 | "engines": { 299 | "node": ">=10" 300 | }, 301 | "funding": { 302 | "url": "https://github.com/sponsors/sindresorhus" 303 | } 304 | }, 305 | "node_modules/chai": { 306 | "version": "4.3.10", 307 | "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.10.tgz", 308 | "integrity": "sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==", 309 | "dev": true, 310 | "dependencies": { 311 | "assertion-error": "^1.1.0", 312 | "check-error": "^1.0.3", 313 | "deep-eql": "^4.1.3", 314 | "get-func-name": "^2.0.2", 315 | "loupe": "^2.3.6", 316 | "pathval": "^1.1.1", 317 | "type-detect": "^4.0.8" 318 | }, 319 | "engines": { 320 | "node": ">=4" 321 | } 322 | }, 323 | "node_modules/chalk": { 324 | "version": "4.1.2", 325 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", 326 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 327 | "dev": true, 328 | "dependencies": { 329 | "ansi-styles": "^4.1.0", 330 | "supports-color": "^7.1.0" 331 | }, 332 | "engines": { 333 | "node": ">=10" 334 | }, 335 | "funding": { 336 | "url": "https://github.com/chalk/chalk?sponsor=1" 337 | } 338 | }, 339 | "node_modules/chalk/node_modules/supports-color": { 340 | "version": "7.2.0", 341 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 342 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 343 | "dev": true, 344 | "dependencies": { 345 | "has-flag": "^4.0.0" 346 | }, 347 | "engines": { 348 | "node": ">=8" 349 | } 350 | }, 351 | "node_modules/check-error": { 352 | "version": "1.0.3", 353 | "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", 354 | "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", 355 | "dev": true, 356 | "dependencies": { 357 | "get-func-name": "^2.0.2" 358 | }, 359 | "engines": { 360 | "node": "*" 361 | } 362 | }, 363 | "node_modules/chokidar": { 364 | "version": "3.5.3", 365 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", 366 | "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", 367 | "dev": true, 368 | "funding": [ 369 | { 370 | "type": "individual", 371 | "url": "https://paulmillr.com/funding/" 372 | } 373 | ], 374 | "dependencies": { 375 | "anymatch": "~3.1.2", 376 | "braces": "~3.0.2", 377 | "glob-parent": "~5.1.2", 378 | "is-binary-path": "~2.1.0", 379 | "is-glob": "~4.0.1", 380 | "normalize-path": "~3.0.0", 381 | "readdirp": "~3.6.0" 382 | }, 383 | "engines": { 384 | "node": ">= 8.10.0" 385 | }, 386 | "optionalDependencies": { 387 | "fsevents": "~2.3.2" 388 | } 389 | }, 390 | "node_modules/cliui": { 391 | "version": "7.0.4", 392 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", 393 | "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", 394 | "dev": true, 395 | "dependencies": { 396 | "string-width": "^4.2.0", 397 | "strip-ansi": "^6.0.0", 398 | "wrap-ansi": "^7.0.0" 399 | } 400 | }, 401 | "node_modules/color-convert": { 402 | "version": "2.0.1", 403 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 404 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 405 | "dev": true, 406 | "dependencies": { 407 | "color-name": "~1.1.4" 408 | }, 409 | "engines": { 410 | "node": ">=7.0.0" 411 | } 412 | }, 413 | "node_modules/color-name": { 414 | "version": "1.1.4", 415 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 416 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 417 | "dev": true 418 | }, 419 | "node_modules/concat-map": { 420 | "version": "0.0.1", 421 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 422 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", 423 | "dev": true 424 | }, 425 | "node_modules/debug": { 426 | "version": "4.3.4", 427 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 428 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 429 | "dev": true, 430 | "dependencies": { 431 | "ms": "2.1.2" 432 | }, 433 | "engines": { 434 | "node": ">=6.0" 435 | }, 436 | "peerDependenciesMeta": { 437 | "supports-color": { 438 | "optional": true 439 | } 440 | } 441 | }, 442 | "node_modules/debug/node_modules/ms": { 443 | "version": "2.1.2", 444 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 445 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 446 | "dev": true 447 | }, 448 | "node_modules/decamelize": { 449 | "version": "4.0.0", 450 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", 451 | "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", 452 | "dev": true, 453 | "engines": { 454 | "node": ">=10" 455 | }, 456 | "funding": { 457 | "url": "https://github.com/sponsors/sindresorhus" 458 | } 459 | }, 460 | "node_modules/deep-eql": { 461 | "version": "4.1.3", 462 | "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", 463 | "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", 464 | "dev": true, 465 | "dependencies": { 466 | "type-detect": "^4.0.0" 467 | }, 468 | "engines": { 469 | "node": ">=6" 470 | } 471 | }, 472 | "node_modules/deprecation": { 473 | "version": "2.3.1", 474 | "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", 475 | "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" 476 | }, 477 | "node_modules/diff": { 478 | "version": "5.0.0", 479 | "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", 480 | "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", 481 | "dev": true, 482 | "engines": { 483 | "node": ">=0.3.1" 484 | } 485 | }, 486 | "node_modules/emoji-regex": { 487 | "version": "8.0.0", 488 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 489 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 490 | "dev": true 491 | }, 492 | "node_modules/escalade": { 493 | "version": "3.1.1", 494 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", 495 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", 496 | "dev": true, 497 | "engines": { 498 | "node": ">=6" 499 | } 500 | }, 501 | "node_modules/escape-string-regexp": { 502 | "version": "4.0.0", 503 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", 504 | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", 505 | "dev": true, 506 | "engines": { 507 | "node": ">=10" 508 | }, 509 | "funding": { 510 | "url": "https://github.com/sponsors/sindresorhus" 511 | } 512 | }, 513 | "node_modules/fill-range": { 514 | "version": "7.0.1", 515 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 516 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 517 | "dev": true, 518 | "dependencies": { 519 | "to-regex-range": "^5.0.1" 520 | }, 521 | "engines": { 522 | "node": ">=8" 523 | } 524 | }, 525 | "node_modules/find-up": { 526 | "version": "5.0.0", 527 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", 528 | "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", 529 | "dev": true, 530 | "dependencies": { 531 | "locate-path": "^6.0.0", 532 | "path-exists": "^4.0.0" 533 | }, 534 | "engines": { 535 | "node": ">=10" 536 | }, 537 | "funding": { 538 | "url": "https://github.com/sponsors/sindresorhus" 539 | } 540 | }, 541 | "node_modules/flat": { 542 | "version": "5.0.2", 543 | "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", 544 | "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", 545 | "dev": true, 546 | "bin": { 547 | "flat": "cli.js" 548 | } 549 | }, 550 | "node_modules/fs.realpath": { 551 | "version": "1.0.0", 552 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 553 | "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", 554 | "dev": true 555 | }, 556 | "node_modules/fsevents": { 557 | "version": "2.3.3", 558 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 559 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 560 | "dev": true, 561 | "hasInstallScript": true, 562 | "optional": true, 563 | "os": [ 564 | "darwin" 565 | ], 566 | "engines": { 567 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 568 | } 569 | }, 570 | "node_modules/get-caller-file": { 571 | "version": "2.0.5", 572 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", 573 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", 574 | "dev": true, 575 | "engines": { 576 | "node": "6.* || 8.* || >= 10.*" 577 | } 578 | }, 579 | "node_modules/get-func-name": { 580 | "version": "2.0.2", 581 | "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", 582 | "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", 583 | "dev": true, 584 | "engines": { 585 | "node": "*" 586 | } 587 | }, 588 | "node_modules/glob": { 589 | "version": "7.2.0", 590 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", 591 | "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", 592 | "dev": true, 593 | "dependencies": { 594 | "fs.realpath": "^1.0.0", 595 | "inflight": "^1.0.4", 596 | "inherits": "2", 597 | "minimatch": "^3.0.4", 598 | "once": "^1.3.0", 599 | "path-is-absolute": "^1.0.0" 600 | }, 601 | "engines": { 602 | "node": "*" 603 | }, 604 | "funding": { 605 | "url": "https://github.com/sponsors/isaacs" 606 | } 607 | }, 608 | "node_modules/glob-parent": { 609 | "version": "5.1.2", 610 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 611 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 612 | "dev": true, 613 | "dependencies": { 614 | "is-glob": "^4.0.1" 615 | }, 616 | "engines": { 617 | "node": ">= 6" 618 | } 619 | }, 620 | "node_modules/glob/node_modules/brace-expansion": { 621 | "version": "1.1.11", 622 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 623 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 624 | "dev": true, 625 | "dependencies": { 626 | "balanced-match": "^1.0.0", 627 | "concat-map": "0.0.1" 628 | } 629 | }, 630 | "node_modules/glob/node_modules/minimatch": { 631 | "version": "3.1.2", 632 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 633 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 634 | "dev": true, 635 | "dependencies": { 636 | "brace-expansion": "^1.1.7" 637 | }, 638 | "engines": { 639 | "node": "*" 640 | } 641 | }, 642 | "node_modules/has-flag": { 643 | "version": "4.0.0", 644 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 645 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 646 | "dev": true, 647 | "engines": { 648 | "node": ">=8" 649 | } 650 | }, 651 | "node_modules/he": { 652 | "version": "1.2.0", 653 | "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", 654 | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", 655 | "dev": true, 656 | "bin": { 657 | "he": "bin/he" 658 | } 659 | }, 660 | "node_modules/inflight": { 661 | "version": "1.0.6", 662 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 663 | "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", 664 | "dev": true, 665 | "dependencies": { 666 | "once": "^1.3.0", 667 | "wrappy": "1" 668 | } 669 | }, 670 | "node_modules/inherits": { 671 | "version": "2.0.4", 672 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 673 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 674 | "dev": true 675 | }, 676 | "node_modules/is-binary-path": { 677 | "version": "2.1.0", 678 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 679 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 680 | "dev": true, 681 | "dependencies": { 682 | "binary-extensions": "^2.0.0" 683 | }, 684 | "engines": { 685 | "node": ">=8" 686 | } 687 | }, 688 | "node_modules/is-extglob": { 689 | "version": "2.1.1", 690 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 691 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 692 | "dev": true, 693 | "engines": { 694 | "node": ">=0.10.0" 695 | } 696 | }, 697 | "node_modules/is-fullwidth-code-point": { 698 | "version": "3.0.0", 699 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 700 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 701 | "dev": true, 702 | "engines": { 703 | "node": ">=8" 704 | } 705 | }, 706 | "node_modules/is-glob": { 707 | "version": "4.0.3", 708 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 709 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 710 | "dev": true, 711 | "dependencies": { 712 | "is-extglob": "^2.1.1" 713 | }, 714 | "engines": { 715 | "node": ">=0.10.0" 716 | } 717 | }, 718 | "node_modules/is-number": { 719 | "version": "7.0.0", 720 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 721 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 722 | "dev": true, 723 | "engines": { 724 | "node": ">=0.12.0" 725 | } 726 | }, 727 | "node_modules/is-plain-obj": { 728 | "version": "2.1.0", 729 | "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", 730 | "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", 731 | "dev": true, 732 | "engines": { 733 | "node": ">=8" 734 | } 735 | }, 736 | "node_modules/is-unicode-supported": { 737 | "version": "0.1.0", 738 | "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", 739 | "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", 740 | "dev": true, 741 | "engines": { 742 | "node": ">=10" 743 | }, 744 | "funding": { 745 | "url": "https://github.com/sponsors/sindresorhus" 746 | } 747 | }, 748 | "node_modules/js-yaml": { 749 | "version": "4.1.0", 750 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", 751 | "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", 752 | "dev": true, 753 | "dependencies": { 754 | "argparse": "^2.0.1" 755 | }, 756 | "bin": { 757 | "js-yaml": "bin/js-yaml.js" 758 | } 759 | }, 760 | "node_modules/locate-path": { 761 | "version": "6.0.0", 762 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", 763 | "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", 764 | "dev": true, 765 | "dependencies": { 766 | "p-locate": "^5.0.0" 767 | }, 768 | "engines": { 769 | "node": ">=10" 770 | }, 771 | "funding": { 772 | "url": "https://github.com/sponsors/sindresorhus" 773 | } 774 | }, 775 | "node_modules/log-symbols": { 776 | "version": "4.1.0", 777 | "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", 778 | "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", 779 | "dev": true, 780 | "dependencies": { 781 | "chalk": "^4.1.0", 782 | "is-unicode-supported": "^0.1.0" 783 | }, 784 | "engines": { 785 | "node": ">=10" 786 | }, 787 | "funding": { 788 | "url": "https://github.com/sponsors/sindresorhus" 789 | } 790 | }, 791 | "node_modules/loupe": { 792 | "version": "2.3.7", 793 | "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", 794 | "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", 795 | "dev": true, 796 | "dependencies": { 797 | "get-func-name": "^2.0.1" 798 | } 799 | }, 800 | "node_modules/minimatch": { 801 | "version": "5.0.1", 802 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", 803 | "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", 804 | "dev": true, 805 | "dependencies": { 806 | "brace-expansion": "^2.0.1" 807 | }, 808 | "engines": { 809 | "node": ">=10" 810 | } 811 | }, 812 | "node_modules/mocha": { 813 | "version": "10.2.0", 814 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", 815 | "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", 816 | "dev": true, 817 | "dependencies": { 818 | "ansi-colors": "4.1.1", 819 | "browser-stdout": "1.3.1", 820 | "chokidar": "3.5.3", 821 | "debug": "4.3.4", 822 | "diff": "5.0.0", 823 | "escape-string-regexp": "4.0.0", 824 | "find-up": "5.0.0", 825 | "glob": "7.2.0", 826 | "he": "1.2.0", 827 | "js-yaml": "4.1.0", 828 | "log-symbols": "4.1.0", 829 | "minimatch": "5.0.1", 830 | "ms": "2.1.3", 831 | "nanoid": "3.3.3", 832 | "serialize-javascript": "6.0.0", 833 | "strip-json-comments": "3.1.1", 834 | "supports-color": "8.1.1", 835 | "workerpool": "6.2.1", 836 | "yargs": "16.2.0", 837 | "yargs-parser": "20.2.4", 838 | "yargs-unparser": "2.0.0" 839 | }, 840 | "bin": { 841 | "_mocha": "bin/_mocha", 842 | "mocha": "bin/mocha.js" 843 | }, 844 | "engines": { 845 | "node": ">= 14.0.0" 846 | }, 847 | "funding": { 848 | "type": "opencollective", 849 | "url": "https://opencollective.com/mochajs" 850 | } 851 | }, 852 | "node_modules/ms": { 853 | "version": "2.1.3", 854 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 855 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 856 | "dev": true 857 | }, 858 | "node_modules/nanoid": { 859 | "version": "3.3.3", 860 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", 861 | "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", 862 | "dev": true, 863 | "bin": { 864 | "nanoid": "bin/nanoid.cjs" 865 | }, 866 | "engines": { 867 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 868 | } 869 | }, 870 | "node_modules/normalize-path": { 871 | "version": "3.0.0", 872 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 873 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 874 | "dev": true, 875 | "engines": { 876 | "node": ">=0.10.0" 877 | } 878 | }, 879 | "node_modules/once": { 880 | "version": "1.4.0", 881 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 882 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 883 | "dependencies": { 884 | "wrappy": "1" 885 | } 886 | }, 887 | "node_modules/p-limit": { 888 | "version": "3.1.0", 889 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", 890 | "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", 891 | "dev": true, 892 | "dependencies": { 893 | "yocto-queue": "^0.1.0" 894 | }, 895 | "engines": { 896 | "node": ">=10" 897 | }, 898 | "funding": { 899 | "url": "https://github.com/sponsors/sindresorhus" 900 | } 901 | }, 902 | "node_modules/p-locate": { 903 | "version": "5.0.0", 904 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", 905 | "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", 906 | "dev": true, 907 | "dependencies": { 908 | "p-limit": "^3.0.2" 909 | }, 910 | "engines": { 911 | "node": ">=10" 912 | }, 913 | "funding": { 914 | "url": "https://github.com/sponsors/sindresorhus" 915 | } 916 | }, 917 | "node_modules/path-exists": { 918 | "version": "4.0.0", 919 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", 920 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", 921 | "dev": true, 922 | "engines": { 923 | "node": ">=8" 924 | } 925 | }, 926 | "node_modules/path-is-absolute": { 927 | "version": "1.0.1", 928 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 929 | "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", 930 | "dev": true, 931 | "engines": { 932 | "node": ">=0.10.0" 933 | } 934 | }, 935 | "node_modules/pathval": { 936 | "version": "1.1.1", 937 | "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", 938 | "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", 939 | "dev": true, 940 | "engines": { 941 | "node": "*" 942 | } 943 | }, 944 | "node_modules/picomatch": { 945 | "version": "2.3.1", 946 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 947 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 948 | "dev": true, 949 | "engines": { 950 | "node": ">=8.6" 951 | }, 952 | "funding": { 953 | "url": "https://github.com/sponsors/jonschlinkert" 954 | } 955 | }, 956 | "node_modules/randombytes": { 957 | "version": "2.1.0", 958 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", 959 | "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", 960 | "dev": true, 961 | "dependencies": { 962 | "safe-buffer": "^5.1.0" 963 | } 964 | }, 965 | "node_modules/readdirp": { 966 | "version": "3.6.0", 967 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 968 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 969 | "dev": true, 970 | "dependencies": { 971 | "picomatch": "^2.2.1" 972 | }, 973 | "engines": { 974 | "node": ">=8.10.0" 975 | } 976 | }, 977 | "node_modules/require-directory": { 978 | "version": "2.1.1", 979 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 980 | "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", 981 | "dev": true, 982 | "engines": { 983 | "node": ">=0.10.0" 984 | } 985 | }, 986 | "node_modules/safe-buffer": { 987 | "version": "5.2.1", 988 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 989 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 990 | "dev": true, 991 | "funding": [ 992 | { 993 | "type": "github", 994 | "url": "https://github.com/sponsors/feross" 995 | }, 996 | { 997 | "type": "patreon", 998 | "url": "https://www.patreon.com/feross" 999 | }, 1000 | { 1001 | "type": "consulting", 1002 | "url": "https://feross.org/support" 1003 | } 1004 | ] 1005 | }, 1006 | "node_modules/serialize-javascript": { 1007 | "version": "6.0.0", 1008 | "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", 1009 | "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", 1010 | "dev": true, 1011 | "dependencies": { 1012 | "randombytes": "^2.1.0" 1013 | } 1014 | }, 1015 | "node_modules/string-width": { 1016 | "version": "4.2.3", 1017 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 1018 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 1019 | "dev": true, 1020 | "dependencies": { 1021 | "emoji-regex": "^8.0.0", 1022 | "is-fullwidth-code-point": "^3.0.0", 1023 | "strip-ansi": "^6.0.1" 1024 | }, 1025 | "engines": { 1026 | "node": ">=8" 1027 | } 1028 | }, 1029 | "node_modules/strip-ansi": { 1030 | "version": "6.0.1", 1031 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 1032 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 1033 | "dev": true, 1034 | "dependencies": { 1035 | "ansi-regex": "^5.0.1" 1036 | }, 1037 | "engines": { 1038 | "node": ">=8" 1039 | } 1040 | }, 1041 | "node_modules/strip-json-comments": { 1042 | "version": "3.1.1", 1043 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", 1044 | "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", 1045 | "dev": true, 1046 | "engines": { 1047 | "node": ">=8" 1048 | }, 1049 | "funding": { 1050 | "url": "https://github.com/sponsors/sindresorhus" 1051 | } 1052 | }, 1053 | "node_modules/supports-color": { 1054 | "version": "8.1.1", 1055 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", 1056 | "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", 1057 | "dev": true, 1058 | "dependencies": { 1059 | "has-flag": "^4.0.0" 1060 | }, 1061 | "engines": { 1062 | "node": ">=10" 1063 | }, 1064 | "funding": { 1065 | "url": "https://github.com/chalk/supports-color?sponsor=1" 1066 | } 1067 | }, 1068 | "node_modules/to-regex-range": { 1069 | "version": "5.0.1", 1070 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 1071 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 1072 | "dev": true, 1073 | "dependencies": { 1074 | "is-number": "^7.0.0" 1075 | }, 1076 | "engines": { 1077 | "node": ">=8.0" 1078 | } 1079 | }, 1080 | "node_modules/tunnel": { 1081 | "version": "0.0.6", 1082 | "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", 1083 | "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", 1084 | "engines": { 1085 | "node": ">=0.6.11 <=0.7.0 || >=0.7.3" 1086 | } 1087 | }, 1088 | "node_modules/type-detect": { 1089 | "version": "4.0.8", 1090 | "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", 1091 | "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", 1092 | "dev": true, 1093 | "engines": { 1094 | "node": ">=4" 1095 | } 1096 | }, 1097 | "node_modules/undici": { 1098 | "version": "5.28.2", 1099 | "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.2.tgz", 1100 | "integrity": "sha512-wh1pHJHnUeQV5Xa8/kyQhO7WFa8M34l026L5P/+2TYiakvGy5Rdc8jWZVyG7ieht/0WgJLEd3kcU5gKx+6GC8w==", 1101 | "dependencies": { 1102 | "@fastify/busboy": "^2.0.0" 1103 | }, 1104 | "engines": { 1105 | "node": ">=14.0" 1106 | } 1107 | }, 1108 | "node_modules/universal-user-agent": { 1109 | "version": "6.0.1", 1110 | "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz", 1111 | "integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==" 1112 | }, 1113 | "node_modules/uuid": { 1114 | "version": "8.3.2", 1115 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", 1116 | "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", 1117 | "bin": { 1118 | "uuid": "dist/bin/uuid" 1119 | } 1120 | }, 1121 | "node_modules/workerpool": { 1122 | "version": "6.2.1", 1123 | "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", 1124 | "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", 1125 | "dev": true 1126 | }, 1127 | "node_modules/wrap-ansi": { 1128 | "version": "7.0.0", 1129 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 1130 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 1131 | "dev": true, 1132 | "dependencies": { 1133 | "ansi-styles": "^4.0.0", 1134 | "string-width": "^4.1.0", 1135 | "strip-ansi": "^6.0.0" 1136 | }, 1137 | "engines": { 1138 | "node": ">=10" 1139 | }, 1140 | "funding": { 1141 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1" 1142 | } 1143 | }, 1144 | "node_modules/wrappy": { 1145 | "version": "1.0.2", 1146 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1147 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" 1148 | }, 1149 | "node_modules/y18n": { 1150 | "version": "5.0.8", 1151 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", 1152 | "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", 1153 | "dev": true, 1154 | "engines": { 1155 | "node": ">=10" 1156 | } 1157 | }, 1158 | "node_modules/yargs": { 1159 | "version": "16.2.0", 1160 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", 1161 | "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", 1162 | "dev": true, 1163 | "dependencies": { 1164 | "cliui": "^7.0.2", 1165 | "escalade": "^3.1.1", 1166 | "get-caller-file": "^2.0.5", 1167 | "require-directory": "^2.1.1", 1168 | "string-width": "^4.2.0", 1169 | "y18n": "^5.0.5", 1170 | "yargs-parser": "^20.2.2" 1171 | }, 1172 | "engines": { 1173 | "node": ">=10" 1174 | } 1175 | }, 1176 | "node_modules/yargs-parser": { 1177 | "version": "20.2.4", 1178 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", 1179 | "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", 1180 | "dev": true, 1181 | "engines": { 1182 | "node": ">=10" 1183 | } 1184 | }, 1185 | "node_modules/yargs-unparser": { 1186 | "version": "2.0.0", 1187 | "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", 1188 | "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", 1189 | "dev": true, 1190 | "dependencies": { 1191 | "camelcase": "^6.0.0", 1192 | "decamelize": "^4.0.0", 1193 | "flat": "^5.0.2", 1194 | "is-plain-obj": "^2.1.0" 1195 | }, 1196 | "engines": { 1197 | "node": ">=10" 1198 | } 1199 | }, 1200 | "node_modules/yocto-queue": { 1201 | "version": "0.1.0", 1202 | "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", 1203 | "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", 1204 | "dev": true, 1205 | "engines": { 1206 | "node": ">=10" 1207 | }, 1208 | "funding": { 1209 | "url": "https://github.com/sponsors/sindresorhus" 1210 | } 1211 | } 1212 | } 1213 | } 1214 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "issue-body-parser", 3 | "version": "4.2.1", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "ncc build index.js", 8 | "test": "mocha ./src/**/*.test.js" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/peter-murray/issue-forms-body-parser.git" 13 | }, 14 | "keywords": [], 15 | "author": "", 16 | "license": "MIT", 17 | "bugs": { 18 | "url": "https://github.com/peter-murray/issue-forms-body-parser/issues" 19 | }, 20 | "homepage": "https://github.com/peter-murray/issue-forms-body-parser#readme", 21 | "dependencies": { 22 | "@actions/core": "^1.10.1", 23 | "@actions/github": "^6.0.0" 24 | }, 25 | "devDependencies": { 26 | "@vercel/ncc": "^0.38.1", 27 | "chai": "^4.3.6", 28 | "mocha": "^10.0.0" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/IssueUtil.js: -------------------------------------------------------------------------------- 1 | const github = require('@actions/github'); 2 | 3 | module.exports = class IssueUtil { 4 | 5 | constructor(token) { 6 | if (!token) { 7 | core.error('Failed to provide a GitHub token for accessing the GitHub REST API.'); 8 | } 9 | this.octokit = github.getOctokit(token); 10 | } 11 | 12 | async getIssueBody(repository, id) { 13 | const repo = this.getRepoObject(repository); 14 | 15 | return this.octokit.rest.issues.get({ 16 | ...repo, 17 | issue_number: id 18 | }).then(result => { 19 | if (result.status !== 200) { 20 | throw new Error(`Unexpected status code from retrieving issue: ${result.status}`); 21 | } 22 | return result.data.body; 23 | }).catch(err => { 24 | throw err; 25 | }); 26 | } 27 | 28 | getRepoObject(repository) { 29 | if (!repository) { 30 | throw new Error(`Repository must be specified, but was '${repository}'`); 31 | } 32 | 33 | const [owner, repo] = repository.split('/'); 34 | if (!repo) { 35 | throw new Error(`The repository reference must be in the form of 'owner/repo', but suppied value was '${repository}'`); 36 | } 37 | 38 | return { 39 | owner, 40 | repo 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /src/Parser.js: -------------------------------------------------------------------------------- 1 | // The entry when a user has not provided a value in response 2 | const NO_RESPONSE = '_No response_'; 3 | 4 | module.exports = class Parser { 5 | 6 | constructor(separator, openTag, closeTag) { 7 | this._config = { 8 | separator: separator, 9 | tag: { 10 | open: openTag, 11 | close: closeTag 12 | } 13 | } 14 | } 15 | 16 | get separator() { 17 | return this._config.separator; 18 | } 19 | 20 | get tagRegex() { 21 | const open = this._config.tag.open 22 | , close = this._config.tag.close 23 | , regexMatch = `${open}(.*)${close}(?:\\s)+(.*)` 24 | ; 25 | 26 | const tagRegex = new RegExp(regexMatch, 'sm'); 27 | return tagRegex; 28 | } 29 | 30 | get checkBoxRegex() { 31 | const regexMatch = `\\- \\[(\\s|X|x)\\] (.*)`; 32 | return new RegExp(regexMatch); 33 | } 34 | 35 | parse(content) { 36 | if (!content || content.trim().length === 0) { 37 | return undefined; 38 | } 39 | 40 | // Split up the payload on the specified line separator 41 | const parts = content.split(this.separator); 42 | 43 | const result = {}; 44 | if (parts) { 45 | const tagRegex = this.tagRegex; 46 | const checkBoxRegex = this.checkBoxRegex; 47 | 48 | parts.forEach(part => { 49 | const tagMatch = tagRegex.exec(part); 50 | 51 | if (tagMatch) { 52 | const value = removeHiddenContent(tagMatch[2]).trim(); 53 | 54 | if (value === NO_RESPONSE) { 55 | // no reponse provided in the payload, report no value 56 | result[tagMatch[1]] = undefined; 57 | } else { 58 | // We may have a checkboxes that need to be parsed so check for those 59 | if (checkBoxRegex.exec(value)) { 60 | // Split the content as we may have multiple lines of checkboxes 61 | const contentLines = value.split('\n'); 62 | const checkboxData = {}; 63 | 64 | contentLines.forEach(line => { 65 | const parsed = checkBoxRegex.exec(line); 66 | if (parsed) { 67 | checkboxData[parsed[2]] = parsed[1] === 'X' || parsed[1] === 'x'; 68 | } 69 | }); 70 | result[tagMatch[1]] = checkboxData; 71 | } else { 72 | result[tagMatch[1]] = value; 73 | } 74 | } 75 | } 76 | }); 77 | } 78 | 79 | return result; 80 | } 81 | } 82 | 83 | function removeHiddenContent(value) { 84 | return value.replace(//g, ''); 85 | } -------------------------------------------------------------------------------- /src/Parser.test.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | , fs = require('fs') 3 | , expect = require('chai').expect 4 | , Parser = require('./Parser') 5 | ; 6 | 7 | describe('Parser', () => { 8 | 9 | describe('parse()', () => { 10 | 11 | it('should parse same open/close tags', () => { 12 | const parser = new Parser('###', '>>', '>>'); 13 | validateResults(parser.parse(loadFileData('demo_same_open_close.txt'))); 14 | }); 15 | 16 | it('should parse prem test', () => { 17 | const parser = new Parser('###', '>>', '<<'); 18 | const payload = parser.parse(loadFileData('prem_test.txt')); 19 | 20 | expect(payload).to.have.property('Location').to.equal('London'); 21 | expect(payload).to.have.property('Partner Organization Name').to.equal('all-your-consult'); 22 | expect(payload).to.have.property('Status').to.equal('🟢 Green - On track to meet goals 🏝️'); 23 | 24 | expect(payload).to.have.property('Languages').to.be.instanceOf(Object); 25 | const languages = payload.Languages; 26 | expect(Object.keys(languages)).to.have.length(11); 27 | expect(languages).to.have.property('English').to.be.true; 28 | expect(languages).to.have.property('French').to.be.true; 29 | expect(languages).to.have.property('Italian').to.be.true; 30 | expect(languages).to.have.property('German').to.be.false; 31 | expect(languages).to.have.property('Korean').to.be.false; 32 | expect(languages).to.have.property('Spanish').to.be.false 33 | }); 34 | 35 | 36 | it('should parse different open/close tags', () => { 37 | const parser = new Parser('###', '>>', '<<'); 38 | validateResults(parser.parse(loadFileData('demo_different_open_close.txt'))); 39 | }); 40 | 41 | 42 | it('should ignore no response fields', () => { 43 | const parser = new Parser('###', '>>>', '<<<'); 44 | const results = parser.parse(loadFileData('demo_missing_responses.txt')); 45 | 46 | expect(results).to.have.property('demo-repository-owner').to.equal('octodemo'); 47 | expect(results).to.have.property('demo-repository-name').to.equal('pm-automation-test-001'); 48 | expect(results).to.have.property('template').to.be.undefined; 49 | }); 50 | 51 | 52 | // it('should parse a checkbox that is disabled', () => { 53 | // const parser = new Parser('###', '>>>', '<<<'); 54 | // const results = parser.parse(loadFileData('demo_checkbox_disabled.txt')); 55 | 56 | // expect(results).to.have.property('demo-repository-owner').to.equal('octodemo'); 57 | // expect(results).to.have.property('demo-repository-name').to.equal('pm-testing-workflow-004'); 58 | // expect(results).to.have.property('template').to.equal('octodemo/template-bookstore-v2'); 59 | // expect(results).to.have.property('template-branch').to.be.undefined; 60 | // expect(results).to.have.property('demo-config-create-project').to.be.false; 61 | // }); 62 | 63 | // it('should parse a checkbox that is enabled', () => { 64 | // const parser = new Parser('###', '>>>', '<<<'); 65 | // const results = parser.parse(loadFileData('demo_checkbox_enabled.txt')); 66 | 67 | // expect(results).to.have.property('demo-repository-owner').to.equal('octodemo'); 68 | // expect(results).to.have.property('demo-repository-name').to.equal('pm-testing-workflow-003'); 69 | // expect(results).to.have.property('template').to.equal('octodemo/template-bookstore-v2'); 70 | // expect(results).to.have.property('template-branch').to.be.undefined; 71 | // expect(results).to.have.property('demo-config-create-project').to.be.true; 72 | // }); 73 | 74 | it('should parse a checkbox example', () => { 75 | const parser = new Parser('###', '>>>', '<<<'); 76 | const results = parser.parse(loadFileData('example_with_checkboxes.txt')); 77 | 78 | expect(results).to.have.property('demo-repository-owner').to.equal('octodemo'); 79 | expect(results).to.have.property('demo-repository-name').to.equal('test'); 80 | expect(results).to.have.property('template').to.equal('octodemo/template-bookstore-v2'); 81 | expect(results).to.have.property('template-branch').to.be.undefined; 82 | expect(results).to.have.property('Demo custom configuration'); 83 | 84 | const config = results['Demo custom configuration']; 85 | expect(config).to.have.property('testing').to.be.true; 86 | expect(config).to.have.property('projects_enabled').to.be.false; 87 | expect(config).to.have.property('issues_enabled').to.be.true; 88 | }); 89 | 90 | it('should parse checkbox example 2', () => { 91 | const parser = new Parser('###', '>>>', '<<<'); 92 | const results = parser.parse(loadFileData('example_with_checkboxes_2.txt')); 93 | 94 | expect(results).to.have.property('demo-repository-owner').to.equal('octodemo'); 95 | expect(results).to.have.property('demo-repository-name').to.equal('test'); 96 | expect(results).to.have.property('template').to.equal('octodemo/template-bookstore-v2'); 97 | expect(results).to.have.property('template-branch').to.be.undefined; 98 | expect(results).to.have.property('Demo custom configuration'); 99 | 100 | const config = results['Demo custom configuration']; 101 | expect(config).to.have.property('testing').to.be.false; 102 | expect(config).to.have.property('projects_enabled').to.be.false; 103 | expect(config).to.have.property('issues_enabled').to.be.true; 104 | }); 105 | 106 | it('should parse inputs with hidden data', () => { 107 | const parser = new Parser('###', '>>', '<<'); 108 | const results = parser.parse(loadFileData('example_with_hidden_metadata.txt')); 109 | 110 | expect(results).to.have.property('demo-repository-owner').to.equal('octodemo'); 111 | expect(results).to.have.property('template-type').to.equal('repository'); 112 | expect(results).to.have.property('template-owner').to.equal('octodemo-resources'); 113 | expect(results).to.have.property('template-repo').to.equal('tmpl_bookstore_v3'); 114 | }); 115 | }); 116 | }); 117 | 118 | function validateResults(results) { 119 | expect(results).to.have.property('demo-repository-owner').to.equal('octodemo'); 120 | expect(results).to.have.property('demo-repository-name').to.equal('pm-automation-test-001'); 121 | expect(results).to.have.property('template').to.equal('octodemo/template-demo-github-user-search'); 122 | } 123 | 124 | function loadFileData(file) { 125 | const fileFullPath = path.join(__dirname, 'test_data', file); 126 | return fs.readFileSync(fileFullPath).toString('utf8'); 127 | } -------------------------------------------------------------------------------- /src/test_data/demo_checkbox_disabled.txt: -------------------------------------------------------------------------------- 1 | ### >>>demo-repository-owner<<< 2 | 3 | octodemo 4 | 5 | ### >>>demo-repository-name<<< 6 | 7 | pm-testing-workflow-004 8 | 9 | ### >>>template<<< 10 | 11 | octodemo/template-bookstore-v2 12 | 13 | ### >>>template-branch<<< 14 | 15 | _No response_ 16 | 17 | ### Demo custom configuration 18 | 19 | - [ ] >>>demo-config-create-project<<< -------------------------------------------------------------------------------- /src/test_data/demo_checkbox_enabled.txt: -------------------------------------------------------------------------------- 1 | ### >>>demo-repository-owner<<< 2 | 3 | octodemo 4 | 5 | ### >>>demo-repository-name<<< 6 | 7 | pm-testing-workflow-003 8 | 9 | ### >>>template<<< 10 | 11 | octodemo/template-bookstore-v2 12 | 13 | ### >>>template-branch<<< 14 | 15 | _No response_ 16 | 17 | ### Demo custom configuration 18 | 19 | - [X] >>>demo-config-create-project<<< -------------------------------------------------------------------------------- /src/test_data/demo_different_open_close.txt: -------------------------------------------------------------------------------- 1 | ### >>demo-repository-owner<< 2 | 3 | octodemo 4 | 5 | ### >>demo-repository-name<< 6 | 7 | pm-automation-test-001 8 | 9 | ### >>template<< 10 | 11 | octodemo/template-demo-github-user-search -------------------------------------------------------------------------------- /src/test_data/demo_missing_responses.txt: -------------------------------------------------------------------------------- 1 | ### >>>demo-repository-owner<<< 2 | 3 | octodemo 4 | 5 | ### >>>demo-repository-name<<< 6 | 7 | pm-automation-test-001 8 | 9 | ### >>>template<<< 10 | 11 | _No response_ -------------------------------------------------------------------------------- /src/test_data/demo_same_open_close.txt: -------------------------------------------------------------------------------- 1 | ### >>demo-repository-owner>> 2 | 3 | octodemo 4 | 5 | ### >>demo-repository-name>> 6 | 7 | pm-automation-test-001 8 | 9 | ### >>template>> 10 | 11 | octodemo/template-demo-github-user-search -------------------------------------------------------------------------------- /src/test_data/example_with_checkboxes.txt: -------------------------------------------------------------------------------- 1 | ### >>>demo-repository-owner<<< 2 | 3 | octodemo 4 | 5 | ### >>>demo-repository-name<<< 6 | 7 | test 8 | 9 | ### >>>template<<< 10 | 11 | octodemo/template-bookstore-v2 12 | 13 | ### >>>template-branch<<< 14 | 15 | _No response_ 16 | 17 | ### >>>Demo custom configuration<<< 18 | 19 | - [X] testing 20 | - [ ] projects_enabled 21 | - [X] issues_enabled -------------------------------------------------------------------------------- /src/test_data/example_with_checkboxes_2.txt: -------------------------------------------------------------------------------- 1 | ### >>>demo-repository-owner<<< 2 | 3 | octodemo 4 | 5 | ### >>>demo-repository-name<<< 6 | 7 | test 8 | 9 | ### >>>template<<< 10 | 11 | octodemo/template-bookstore-v2 12 | 13 | ### >>>template-branch<<< 14 | 15 | _No response_ 16 | 17 | ### >>>Demo custom configuration<<< 18 | 19 | - [ ] testing 20 | - [ ] projects_enabled 21 | - [X] issues_enabled 22 | 23 | ### >>>test-value<<< 24 | 25 | nonce 123435 26 | -------------------------------------------------------------------------------- /src/test_data/example_with_hidden_metadata.txt: -------------------------------------------------------------------------------- 1 | ### >>demo-repository-owner<< 2 | 3 | octodemo 4 | 5 | ### >>template-type<< 6 | 7 | repository 8 | 9 | ### >>template-owner<< 10 | 11 | octodemo-resources 12 | 13 | ### >>template-repo<< 14 | 15 | tmpl_bookstore_v3 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/test_data/prem_test.txt: -------------------------------------------------------------------------------- 1 | ### >>Status<< 2 | 3 | 🟢 Green - On track to meet goals 🏝️ 4 | 5 | ### >>Partner Organization Name<< 6 | 7 | all-your-consult 8 | 9 | ### >>Location<< 10 | 11 | London 12 | 13 | ### >>Country<< 14 | 15 | United Kingdom 16 | 17 | ### >>Markets/Regions Served<< 18 | 19 | Hertfordshire 20 | 21 | ### >>Services Contact<< 22 | 23 | @joebloggs 24 | 25 | ### >>Email Address<< 26 | 27 | user@email.com 28 | 29 | ### >>Best Assigned Roles<< 30 | 31 | _No response_ 32 | 33 | ### >>Is this resource a Technical Trainer<< 34 | 35 | _No response_ 36 | 37 | ### >>Is this resource a FastTrack Consultant<< 38 | 39 | _No response_ 40 | 41 | ### >>SSPA Certified through Microsoft<< 42 | 43 | _No response_ 44 | 45 | ### >>Microsoft Partner Certified<< 46 | 47 | _No response_ 48 | 49 | ### >>Languages<< 50 | 51 | - [X] English 52 | - [X] French 53 | - [ ] German 54 | - [X] Italian 55 | - [ ] Spanish 56 | - [ ] Portuguese 57 | - [ ] Chinese/Mandarin or Cantonese 58 | - [ ] Korean 59 | - [ ] Japanese 60 | - [ ] Hindi 61 | - [ ] Other Languages 62 | 63 | ### >>Government/Local Security Clearance<< 64 | 65 | eg. Tokyo, Japan 66 | 67 | ### >>Completed Verification Workshop<< 68 | 69 | _No response_ 70 | 71 | ### >>Attended GitHub Technical Bootcamp<< 72 | 73 | _No response_ 74 | 75 | ### >>List any other GitHub Training & Enablement<< 76 | 77 | eg. Sales Training... 78 | 79 | ### >>CAM GitHub Handle<< 80 | 81 | _No response_ --------------------------------------------------------------------------------