├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .npmignore ├── LICENSE.md ├── README.md ├── package-lock.json ├── package.json ├── spec └── parser-spec.js └── src ├── atomdoc.js ├── doc.js ├── parser.js └── utils.js /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push] 4 | 5 | env: 6 | CI: true 7 | 8 | jobs: 9 | Test: 10 | strategy: 11 | matrix: 12 | os: [ubuntu-latest, macos-latest, windows-latest] 13 | runs-on: ${{ matrix.os }} 14 | steps: 15 | - uses: actions/checkout@v1 16 | - uses: actions/setup-node@v2 17 | with: 18 | node-version: '14' 19 | - name: Install dependencies 20 | run: npm install 21 | - name: Run tests 22 | run: npm run test 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .DS_Store 3 | npm-debug.log 4 | v8.log 5 | .node-version 6 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .travis.yml 2 | .DS_Store 3 | npm-debug.log 4 | v8.log 5 | spec 6 | .npmignore 7 | *.coffee 8 | .node-version 9 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 GitHub Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ##### Atom and all repositories under Atom will be archived on December 15, 2022. Learn more in our [official announcement](https://github.blog/2022-06-08-sunsetting-atom/) 2 | # AtomDoc parser 3 | [![CI](https://github.com/atom/atomdoc/actions/workflows/ci.yml/badge.svg)](https://github.com/atom/atomdoc/actions/workflows/ci.yml) 4 | 5 | Parse atomdoc with JavaScript / CoffeeScript. 6 | 7 | Atomdoc is a code documentation format based on markdown. The atom team writes a lot of markdown, and its rules are deep in our brains. So rather than adopting some other format we'd need to learn, we decided to build a parser around a few markdown conventions. 8 | 9 | ## Usage 10 | 11 | It's on [npm](https://www.npmjs.org/package/atomdoc). 12 | 13 | ``` 14 | npm install atomdoc 15 | ``` 16 | 17 | It has only one method, `parse`: 18 | 19 | ```coffee 20 | AtomDoc = require 'atomdoc' 21 | 22 | docString = """ 23 | Public: My awesome method that does stuff, but returns nothing and has 24 | no arguments. 25 | """ 26 | doc = AtomDoc.parse(docString) 27 | 28 | # Alternatively, you can avoid parsing "Returns" statements in documentation (useful for class-level documentation): 29 | doc = AtomDoc.parse(docString, {parseReturns: false}) 30 | ``` 31 | 32 | `doc` will be an object: 33 | 34 | ```coffee 35 | { 36 | "visibility": "Public", 37 | "description": "My awesome method that does stuff, but returns nothing and has\nno arguments.", 38 | "summary": "My awesome method that does stuff, but returns nothing and has\nno arguments." 39 | } 40 | ``` 41 | 42 | ### Maximal example 43 | 44 | Using all the features. 45 | 46 | ```coffee 47 | AtomDoc = require 'atomdoc' 48 | 49 | docString = """ 50 | Public: My awesome method that does stuff. 51 | 52 | It does things and stuff and even more things, this is the description. The 53 | next section is the arguments. They can be nested. Useful for explaining the 54 | arguments passed to any callbacks. 55 | 56 | * `count` {Number} representing count 57 | * `callback` {Function} that will be called when finished 58 | * `options` Options {Object} passed to your callback with the options: 59 | * `someOption` A {Bool} 60 | * `anotherOption` Another {Bool} 61 | 62 | ## Events 63 | 64 | ### contents-modified 65 | 66 | Public: Fired when this thing happens. 67 | 68 | * `options` {Object} An options hash 69 | * `someOption` {Object} An options hash 70 | 71 | ## Examples 72 | 73 | This is an example. It can have a description. 74 | 75 | ```coffee 76 | myMethod 20, ({someOption, anotherOption}) -> 77 | console.log someOption, anotherOption 78 | ``` 79 | 80 | Returns null in some cases 81 | Returns an {Object} with these keys: 82 | * `someBool` a {Boolean} 83 | * `someNumber` a {Number} 84 | """ 85 | doc = AtomDoc.parse(docString) 86 | ``` 87 | 88 | `doc` will be an object: 89 | 90 | ```coffee 91 | { 92 | "visibility": "Public", 93 | "summary": "My awesome method that does stuff.", 94 | "description": """ 95 | My awesome method that does stuff. 96 | It does things and stuff and even more things, this is the description. The 97 | next section is the arguments. They can be nested. Useful for explaining the 98 | arguments passed to any callbacks. 99 | """, 100 | "arguments": [ 101 | { 102 | "name": "count", 103 | "description": "{Number} representing count", 104 | "type": "Number", 105 | "isOptional": false 106 | }, 107 | { 108 | "children": [ 109 | { 110 | "name": "options", 111 | "description": "Options {Object} passed to your callback with the options:", 112 | "type": "Object", 113 | "isOptional": false 114 | "children": [ 115 | { 116 | "name": "someOption", 117 | "description": "A {Bool}", 118 | "type": "Bool", 119 | "isOptional": false 120 | }, 121 | { 122 | "name": "anotherOption", 123 | "description": "Another {Bool}", 124 | "type": "Bool", 125 | "isOptional": false 126 | } 127 | ], 128 | } 129 | ], 130 | "name": "callback", 131 | "description": "{Function} that will be called when finished", 132 | "type": "Function", 133 | "isOptional": false 134 | } 135 | ], 136 | "events": [ 137 | { 138 | "name": "contents-modified", 139 | "summary": "Fired when this thing happens.", 140 | "description": "Fired when this thing happens.", 141 | "visibility": "Public", 142 | "arguments": [ 143 | { 144 | "children": [ 145 | { 146 | "name": "someOption", 147 | "description": "{Object} An options hash", 148 | "type": "Object", 149 | "isOptional": false 150 | } 151 | ], 152 | "name": "options", 153 | "description": "{Object} An options hash", 154 | "type": "Object", 155 | "isOptional": false 156 | } 157 | ] 158 | } 159 | ], 160 | "examples": [ 161 | { 162 | "description": "This is an example. It can have a description", 163 | "lang": "coffee", 164 | "code": "myMethod 20, ({someOption, anotherOption}) ->\n console.log someOption, anotherOption", 165 | "raw": "```coffee\nmyMethod 20, ({someOption, anotherOption}) ->\n console.log someOption, anotherOption\n```" 166 | } 167 | ], 168 | "returnValues": [ 169 | { 170 | "type": null, 171 | "description": "Returns null in some case" 172 | }, 173 | { 174 | "type": "Object", 175 | "description": "Returns an {Object} with the keys:\n\n* `someBool` a {Boolean}\n* `someNumber` a {Number}" 176 | } 177 | ] 178 | } 179 | ``` 180 | 181 | ## Notes 182 | 183 | The parser uses [marked][marked]'s lexer. 184 | 185 | 186 | [marked]: https://github.com/chjj/marked 187 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "atomdoc", 3 | "version": "1.2.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "acorn": { 8 | "version": "5.7.3", 9 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", 10 | "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", 11 | "dev": true 12 | }, 13 | "acorn-jsx": { 14 | "version": "3.0.1", 15 | "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", 16 | "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", 17 | "dev": true, 18 | "requires": { 19 | "acorn": "^3.0.4" 20 | }, 21 | "dependencies": { 22 | "acorn": { 23 | "version": "3.3.0", 24 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", 25 | "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", 26 | "dev": true 27 | } 28 | } 29 | }, 30 | "ajv": { 31 | "version": "4.11.8", 32 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", 33 | "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", 34 | "dev": true, 35 | "requires": { 36 | "co": "^4.6.0", 37 | "json-stable-stringify": "^1.0.1" 38 | } 39 | }, 40 | "ajv-keywords": { 41 | "version": "1.5.1", 42 | "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz", 43 | "integrity": "sha1-MU3QpLM2j609/NxU7eYXG4htrzw=", 44 | "dev": true 45 | }, 46 | "amdefine": { 47 | "version": "1.0.1", 48 | "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", 49 | "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", 50 | "dev": true 51 | }, 52 | "ansi-escapes": { 53 | "version": "1.4.0", 54 | "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", 55 | "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", 56 | "dev": true 57 | }, 58 | "ansi-regex": { 59 | "version": "2.1.1", 60 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", 61 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", 62 | "dev": true 63 | }, 64 | "ansi-styles": { 65 | "version": "2.2.1", 66 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", 67 | "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", 68 | "dev": true 69 | }, 70 | "argparse": { 71 | "version": "1.0.10", 72 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 73 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 74 | "dev": true, 75 | "requires": { 76 | "sprintf-js": "~1.0.2" 77 | } 78 | }, 79 | "array.prototype.find": { 80 | "version": "2.1.0", 81 | "resolved": "https://registry.npmjs.org/array.prototype.find/-/array.prototype.find-2.1.0.tgz", 82 | "integrity": "sha512-Wn41+K1yuO5p7wRZDl7890c3xvv5UBrfVXTVIe28rSQb6LS0fZMDrQB6PAcxQFRFy6vJTLDc3A2+3CjQdzVKRg==", 83 | "dev": true, 84 | "requires": { 85 | "define-properties": "^1.1.3", 86 | "es-abstract": "^1.13.0" 87 | } 88 | }, 89 | "async": { 90 | "version": "1.5.2", 91 | "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", 92 | "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", 93 | "dev": true 94 | }, 95 | "babel-code-frame": { 96 | "version": "6.26.0", 97 | "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", 98 | "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", 99 | "dev": true, 100 | "requires": { 101 | "chalk": "^1.1.3", 102 | "esutils": "^2.0.2", 103 | "js-tokens": "^3.0.2" 104 | } 105 | }, 106 | "balanced-match": { 107 | "version": "1.0.0", 108 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 109 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 110 | "dev": true 111 | }, 112 | "brace-expansion": { 113 | "version": "1.1.11", 114 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 115 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 116 | "dev": true, 117 | "requires": { 118 | "balanced-match": "^1.0.0", 119 | "concat-map": "0.0.1" 120 | } 121 | }, 122 | "buffer-from": { 123 | "version": "1.1.1", 124 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", 125 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", 126 | "dev": true 127 | }, 128 | "builtin-modules": { 129 | "version": "1.1.1", 130 | "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", 131 | "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", 132 | "dev": true 133 | }, 134 | "caller-path": { 135 | "version": "0.1.0", 136 | "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", 137 | "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", 138 | "dev": true, 139 | "requires": { 140 | "callsites": "^0.2.0" 141 | } 142 | }, 143 | "callsites": { 144 | "version": "0.2.0", 145 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", 146 | "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", 147 | "dev": true 148 | }, 149 | "chalk": { 150 | "version": "1.1.3", 151 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", 152 | "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", 153 | "dev": true, 154 | "requires": { 155 | "ansi-styles": "^2.2.1", 156 | "escape-string-regexp": "^1.0.2", 157 | "has-ansi": "^2.0.0", 158 | "strip-ansi": "^3.0.0", 159 | "supports-color": "^2.0.0" 160 | } 161 | }, 162 | "circular-json": { 163 | "version": "0.3.3", 164 | "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", 165 | "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", 166 | "dev": true 167 | }, 168 | "cli-cursor": { 169 | "version": "1.0.2", 170 | "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", 171 | "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", 172 | "dev": true, 173 | "requires": { 174 | "restore-cursor": "^1.0.1" 175 | } 176 | }, 177 | "cli-width": { 178 | "version": "2.2.0", 179 | "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", 180 | "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", 181 | "dev": true 182 | }, 183 | "co": { 184 | "version": "4.6.0", 185 | "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", 186 | "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", 187 | "dev": true 188 | }, 189 | "code-point-at": { 190 | "version": "1.1.0", 191 | "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", 192 | "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", 193 | "dev": true 194 | }, 195 | "coffee-script": { 196 | "version": "1.12.7", 197 | "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.12.7.tgz", 198 | "integrity": "sha512-fLeEhqwymYat/MpTPUjSKHVYYl0ec2mOyALEMLmzr5i1isuG+6jfI2j2d5oBO3VIzgUXgBVIcOT9uH1TFxBckw==", 199 | "dev": true 200 | }, 201 | "coffeestack": { 202 | "version": "1.2.0", 203 | "resolved": "https://registry.npmjs.org/coffeestack/-/coffeestack-1.2.0.tgz", 204 | "integrity": "sha512-vXT7ZxSZ4lXHh/0A2cODyFqrVIl4Vb0Er5wcS2SrFN4jW8g1qIAmcMsRlRdUKvnvfmKixvENYspAyF/ihWbpyw==", 205 | "dev": true, 206 | "requires": { 207 | "coffee-script": "~1.8.0", 208 | "fs-plus": "^3.1.1", 209 | "source-map": "~0.1.43" 210 | }, 211 | "dependencies": { 212 | "coffee-script": { 213 | "version": "1.8.0", 214 | "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.8.0.tgz", 215 | "integrity": "sha1-nJ8dK0pSoADe0Vtll5FwNkgmPB0=", 216 | "dev": true, 217 | "requires": { 218 | "mkdirp": "~0.3.5" 219 | } 220 | } 221 | } 222 | }, 223 | "concat-map": { 224 | "version": "0.0.1", 225 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 226 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 227 | "dev": true 228 | }, 229 | "concat-stream": { 230 | "version": "1.6.2", 231 | "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", 232 | "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", 233 | "dev": true, 234 | "requires": { 235 | "buffer-from": "^1.0.0", 236 | "inherits": "^2.0.3", 237 | "readable-stream": "^2.2.2", 238 | "typedarray": "^0.0.6" 239 | } 240 | }, 241 | "contains-path": { 242 | "version": "0.1.0", 243 | "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", 244 | "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", 245 | "dev": true 246 | }, 247 | "core-util-is": { 248 | "version": "1.0.2", 249 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 250 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", 251 | "dev": true 252 | }, 253 | "d": { 254 | "version": "1.0.0", 255 | "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", 256 | "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", 257 | "dev": true, 258 | "requires": { 259 | "es5-ext": "^0.10.9" 260 | } 261 | }, 262 | "debug": { 263 | "version": "2.6.9", 264 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 265 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 266 | "dev": true, 267 | "requires": { 268 | "ms": "2.0.0" 269 | } 270 | }, 271 | "debug-log": { 272 | "version": "1.0.1", 273 | "resolved": "https://registry.npmjs.org/debug-log/-/debug-log-1.0.1.tgz", 274 | "integrity": "sha1-IwdjLUwEOCuN+KMvcLiVBG1SdF8=", 275 | "dev": true 276 | }, 277 | "dedent": { 278 | "version": "0.7.0", 279 | "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", 280 | "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", 281 | "dev": true 282 | }, 283 | "deep-is": { 284 | "version": "0.1.3", 285 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", 286 | "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", 287 | "dev": true 288 | }, 289 | "define-properties": { 290 | "version": "1.1.3", 291 | "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", 292 | "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", 293 | "dev": true, 294 | "requires": { 295 | "object-keys": "^1.0.12" 296 | } 297 | }, 298 | "deglob": { 299 | "version": "2.1.1", 300 | "resolved": "https://registry.npmjs.org/deglob/-/deglob-2.1.1.tgz", 301 | "integrity": "sha512-2kjwuGGonL7gWE1XU4Fv79+vVzpoQCl0V+boMwWtOQJV2AGDabCwez++nB1Nli/8BabAfZQ/UuHPlp6AymKdWw==", 302 | "dev": true, 303 | "requires": { 304 | "find-root": "^1.0.0", 305 | "glob": "^7.0.5", 306 | "ignore": "^3.0.9", 307 | "pkg-config": "^1.1.0", 308 | "run-parallel": "^1.1.2", 309 | "uniq": "^1.0.1" 310 | } 311 | }, 312 | "doctrine": { 313 | "version": "2.1.0", 314 | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", 315 | "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", 316 | "dev": true, 317 | "requires": { 318 | "esutils": "^2.0.2" 319 | } 320 | }, 321 | "error-ex": { 322 | "version": "1.3.2", 323 | "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", 324 | "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", 325 | "dev": true, 326 | "requires": { 327 | "is-arrayish": "^0.2.1" 328 | } 329 | }, 330 | "es-abstract": { 331 | "version": "1.13.0", 332 | "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", 333 | "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", 334 | "dev": true, 335 | "requires": { 336 | "es-to-primitive": "^1.2.0", 337 | "function-bind": "^1.1.1", 338 | "has": "^1.0.3", 339 | "is-callable": "^1.1.4", 340 | "is-regex": "^1.0.4", 341 | "object-keys": "^1.0.12" 342 | } 343 | }, 344 | "es-to-primitive": { 345 | "version": "1.2.0", 346 | "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", 347 | "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", 348 | "dev": true, 349 | "requires": { 350 | "is-callable": "^1.1.4", 351 | "is-date-object": "^1.0.1", 352 | "is-symbol": "^1.0.2" 353 | } 354 | }, 355 | "es5-ext": { 356 | "version": "0.10.50", 357 | "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.50.tgz", 358 | "integrity": "sha512-KMzZTPBkeQV/JcSQhI5/z6d9VWJ3EnQ194USTUwIYZ2ZbpN8+SGXQKt1h68EX44+qt+Fzr8DO17vnxrw7c3agw==", 359 | "dev": true, 360 | "requires": { 361 | "es6-iterator": "~2.0.3", 362 | "es6-symbol": "~3.1.1", 363 | "next-tick": "^1.0.0" 364 | } 365 | }, 366 | "es6-iterator": { 367 | "version": "2.0.3", 368 | "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", 369 | "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", 370 | "dev": true, 371 | "requires": { 372 | "d": "1", 373 | "es5-ext": "^0.10.35", 374 | "es6-symbol": "^3.1.1" 375 | } 376 | }, 377 | "es6-map": { 378 | "version": "0.1.5", 379 | "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", 380 | "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", 381 | "dev": true, 382 | "requires": { 383 | "d": "1", 384 | "es5-ext": "~0.10.14", 385 | "es6-iterator": "~2.0.1", 386 | "es6-set": "~0.1.5", 387 | "es6-symbol": "~3.1.1", 388 | "event-emitter": "~0.3.5" 389 | } 390 | }, 391 | "es6-set": { 392 | "version": "0.1.5", 393 | "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", 394 | "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", 395 | "dev": true, 396 | "requires": { 397 | "d": "1", 398 | "es5-ext": "~0.10.14", 399 | "es6-iterator": "~2.0.1", 400 | "es6-symbol": "3.1.1", 401 | "event-emitter": "~0.3.5" 402 | } 403 | }, 404 | "es6-symbol": { 405 | "version": "3.1.1", 406 | "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", 407 | "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", 408 | "dev": true, 409 | "requires": { 410 | "d": "1", 411 | "es5-ext": "~0.10.14" 412 | } 413 | }, 414 | "es6-weak-map": { 415 | "version": "2.0.2", 416 | "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz", 417 | "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", 418 | "dev": true, 419 | "requires": { 420 | "d": "1", 421 | "es5-ext": "^0.10.14", 422 | "es6-iterator": "^2.0.1", 423 | "es6-symbol": "^3.1.1" 424 | } 425 | }, 426 | "escape-string-regexp": { 427 | "version": "1.0.5", 428 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 429 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 430 | "dev": true 431 | }, 432 | "escope": { 433 | "version": "3.6.0", 434 | "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", 435 | "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", 436 | "dev": true, 437 | "requires": { 438 | "es6-map": "^0.1.3", 439 | "es6-weak-map": "^2.0.1", 440 | "esrecurse": "^4.1.0", 441 | "estraverse": "^4.1.1" 442 | } 443 | }, 444 | "eslint": { 445 | "version": "3.19.0", 446 | "resolved": "https://registry.npmjs.org/eslint/-/eslint-3.19.0.tgz", 447 | "integrity": "sha1-yPxiAcf0DdCJQbh8CFdnOGpnmsw=", 448 | "dev": true, 449 | "requires": { 450 | "babel-code-frame": "^6.16.0", 451 | "chalk": "^1.1.3", 452 | "concat-stream": "^1.5.2", 453 | "debug": "^2.1.1", 454 | "doctrine": "^2.0.0", 455 | "escope": "^3.6.0", 456 | "espree": "^3.4.0", 457 | "esquery": "^1.0.0", 458 | "estraverse": "^4.2.0", 459 | "esutils": "^2.0.2", 460 | "file-entry-cache": "^2.0.0", 461 | "glob": "^7.0.3", 462 | "globals": "^9.14.0", 463 | "ignore": "^3.2.0", 464 | "imurmurhash": "^0.1.4", 465 | "inquirer": "^0.12.0", 466 | "is-my-json-valid": "^2.10.0", 467 | "is-resolvable": "^1.0.0", 468 | "js-yaml": "^3.5.1", 469 | "json-stable-stringify": "^1.0.0", 470 | "levn": "^0.3.0", 471 | "lodash": "^4.0.0", 472 | "mkdirp": "^0.5.0", 473 | "natural-compare": "^1.4.0", 474 | "optionator": "^0.8.2", 475 | "path-is-inside": "^1.0.1", 476 | "pluralize": "^1.2.1", 477 | "progress": "^1.1.8", 478 | "require-uncached": "^1.0.2", 479 | "shelljs": "^0.7.5", 480 | "strip-bom": "^3.0.0", 481 | "strip-json-comments": "~2.0.1", 482 | "table": "^3.7.8", 483 | "text-table": "~0.2.0", 484 | "user-home": "^2.0.0" 485 | }, 486 | "dependencies": { 487 | "mkdirp": { 488 | "version": "0.5.1", 489 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 490 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 491 | "dev": true, 492 | "requires": { 493 | "minimist": "0.0.8" 494 | } 495 | } 496 | } 497 | }, 498 | "eslint-config-standard": { 499 | "version": "10.2.1", 500 | "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-10.2.1.tgz", 501 | "integrity": "sha1-wGHk0GbzedwXzVYsZOgZtN1FRZE=", 502 | "dev": true 503 | }, 504 | "eslint-config-standard-jsx": { 505 | "version": "4.0.2", 506 | "resolved": "https://registry.npmjs.org/eslint-config-standard-jsx/-/eslint-config-standard-jsx-4.0.2.tgz", 507 | "integrity": "sha512-F8fRh2WFnTek7dZH9ZaE0PCBwdVGkwVWZmizla/DDNOmg7Tx6B/IlK5+oYpiX29jpu73LszeJj5i1axEZv6VMw==", 508 | "dev": true 509 | }, 510 | "eslint-import-resolver-node": { 511 | "version": "0.2.3", 512 | "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.2.3.tgz", 513 | "integrity": "sha1-Wt2BBujJKNssuiMrzZ76hG49oWw=", 514 | "dev": true, 515 | "requires": { 516 | "debug": "^2.2.0", 517 | "object-assign": "^4.0.1", 518 | "resolve": "^1.1.6" 519 | } 520 | }, 521 | "eslint-module-utils": { 522 | "version": "2.4.0", 523 | "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.4.0.tgz", 524 | "integrity": "sha512-14tltLm38Eu3zS+mt0KvILC3q8jyIAH518MlG+HO0p+yK885Lb1UHTY/UgR91eOyGdmxAPb+OLoW4znqIT6Ndw==", 525 | "dev": true, 526 | "requires": { 527 | "debug": "^2.6.8", 528 | "pkg-dir": "^2.0.0" 529 | } 530 | }, 531 | "eslint-plugin-import": { 532 | "version": "2.2.0", 533 | "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.2.0.tgz", 534 | "integrity": "sha1-crowb60wXWfEgWNIpGmaQimsi04=", 535 | "dev": true, 536 | "requires": { 537 | "builtin-modules": "^1.1.1", 538 | "contains-path": "^0.1.0", 539 | "debug": "^2.2.0", 540 | "doctrine": "1.5.0", 541 | "eslint-import-resolver-node": "^0.2.0", 542 | "eslint-module-utils": "^2.0.0", 543 | "has": "^1.0.1", 544 | "lodash.cond": "^4.3.0", 545 | "minimatch": "^3.0.3", 546 | "pkg-up": "^1.0.0" 547 | }, 548 | "dependencies": { 549 | "doctrine": { 550 | "version": "1.5.0", 551 | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", 552 | "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", 553 | "dev": true, 554 | "requires": { 555 | "esutils": "^2.0.2", 556 | "isarray": "^1.0.0" 557 | } 558 | } 559 | } 560 | }, 561 | "eslint-plugin-node": { 562 | "version": "4.2.3", 563 | "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-4.2.3.tgz", 564 | "integrity": "sha512-vIUQPuwbVYdz/CYnlTLsJrRy7iXHQjdEe5wz0XhhdTym3IInM/zZLlPf9nZ2mThsH0QcsieCOWs2vOeCy/22LQ==", 565 | "dev": true, 566 | "requires": { 567 | "ignore": "^3.0.11", 568 | "minimatch": "^3.0.2", 569 | "object-assign": "^4.0.1", 570 | "resolve": "^1.1.7", 571 | "semver": "5.3.0" 572 | } 573 | }, 574 | "eslint-plugin-promise": { 575 | "version": "3.5.0", 576 | "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-3.5.0.tgz", 577 | "integrity": "sha1-ePu2/+BHIBYnVp6FpsU3OvKmj8o=", 578 | "dev": true 579 | }, 580 | "eslint-plugin-react": { 581 | "version": "6.10.3", 582 | "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-6.10.3.tgz", 583 | "integrity": "sha1-xUNb6wZ3ThLH2y9qut3L+QDNP3g=", 584 | "dev": true, 585 | "requires": { 586 | "array.prototype.find": "^2.0.1", 587 | "doctrine": "^1.2.2", 588 | "has": "^1.0.1", 589 | "jsx-ast-utils": "^1.3.4", 590 | "object.assign": "^4.0.4" 591 | }, 592 | "dependencies": { 593 | "doctrine": { 594 | "version": "1.5.0", 595 | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", 596 | "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", 597 | "dev": true, 598 | "requires": { 599 | "esutils": "^2.0.2", 600 | "isarray": "^1.0.0" 601 | } 602 | } 603 | } 604 | }, 605 | "eslint-plugin-standard": { 606 | "version": "3.0.1", 607 | "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-3.0.1.tgz", 608 | "integrity": "sha1-NNDJFbRe3G8BA5PH7vOCOwhWXPI=", 609 | "dev": true 610 | }, 611 | "espree": { 612 | "version": "3.5.4", 613 | "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", 614 | "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", 615 | "dev": true, 616 | "requires": { 617 | "acorn": "^5.5.0", 618 | "acorn-jsx": "^3.0.0" 619 | } 620 | }, 621 | "esprima": { 622 | "version": "4.0.1", 623 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 624 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", 625 | "dev": true 626 | }, 627 | "esquery": { 628 | "version": "1.0.1", 629 | "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", 630 | "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", 631 | "dev": true, 632 | "requires": { 633 | "estraverse": "^4.0.0" 634 | } 635 | }, 636 | "esrecurse": { 637 | "version": "4.2.1", 638 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", 639 | "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", 640 | "dev": true, 641 | "requires": { 642 | "estraverse": "^4.1.0" 643 | } 644 | }, 645 | "estraverse": { 646 | "version": "4.2.0", 647 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", 648 | "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", 649 | "dev": true 650 | }, 651 | "esutils": { 652 | "version": "2.0.2", 653 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", 654 | "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", 655 | "dev": true 656 | }, 657 | "event-emitter": { 658 | "version": "0.3.5", 659 | "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", 660 | "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", 661 | "dev": true, 662 | "requires": { 663 | "d": "1", 664 | "es5-ext": "~0.10.14" 665 | } 666 | }, 667 | "exit-hook": { 668 | "version": "1.1.1", 669 | "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", 670 | "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=", 671 | "dev": true 672 | }, 673 | "fast-levenshtein": { 674 | "version": "2.0.6", 675 | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", 676 | "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", 677 | "dev": true 678 | }, 679 | "figures": { 680 | "version": "1.7.0", 681 | "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", 682 | "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", 683 | "dev": true, 684 | "requires": { 685 | "escape-string-regexp": "^1.0.5", 686 | "object-assign": "^4.1.0" 687 | } 688 | }, 689 | "file-entry-cache": { 690 | "version": "2.0.0", 691 | "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", 692 | "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", 693 | "dev": true, 694 | "requires": { 695 | "flat-cache": "^1.2.1", 696 | "object-assign": "^4.0.1" 697 | } 698 | }, 699 | "fileset": { 700 | "version": "0.1.8", 701 | "resolved": "https://registry.npmjs.org/fileset/-/fileset-0.1.8.tgz", 702 | "integrity": "sha1-UGuRqTluqn4y+0KoQHfHoMc2t0E=", 703 | "dev": true, 704 | "requires": { 705 | "glob": "3.x", 706 | "minimatch": "0.x" 707 | }, 708 | "dependencies": { 709 | "glob": { 710 | "version": "3.2.11", 711 | "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", 712 | "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", 713 | "dev": true, 714 | "requires": { 715 | "inherits": "2", 716 | "minimatch": "0.3" 717 | }, 718 | "dependencies": { 719 | "minimatch": { 720 | "version": "0.3.0", 721 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", 722 | "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", 723 | "dev": true, 724 | "requires": { 725 | "lru-cache": "2", 726 | "sigmund": "~1.0.0" 727 | } 728 | } 729 | } 730 | }, 731 | "minimatch": { 732 | "version": "0.4.0", 733 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.4.0.tgz", 734 | "integrity": "sha1-vSx9Bg0sjI/Xzefx8u0tWycP2xs=", 735 | "dev": true, 736 | "requires": { 737 | "lru-cache": "2", 738 | "sigmund": "~1.0.0" 739 | } 740 | } 741 | } 742 | }, 743 | "find-root": { 744 | "version": "1.1.0", 745 | "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", 746 | "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", 747 | "dev": true 748 | }, 749 | "find-up": { 750 | "version": "2.1.0", 751 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", 752 | "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", 753 | "dev": true, 754 | "requires": { 755 | "locate-path": "^2.0.0" 756 | } 757 | }, 758 | "flat-cache": { 759 | "version": "1.3.4", 760 | "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", 761 | "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", 762 | "dev": true, 763 | "requires": { 764 | "circular-json": "^0.3.1", 765 | "graceful-fs": "^4.1.2", 766 | "rimraf": "~2.6.2", 767 | "write": "^0.2.1" 768 | } 769 | }, 770 | "fs-plus": { 771 | "version": "3.1.1", 772 | "resolved": "https://registry.npmjs.org/fs-plus/-/fs-plus-3.1.1.tgz", 773 | "integrity": "sha512-Se2PJdOWXqos1qVTkvqqjb0CSnfBnwwD+pq+z4ksT+e97mEShod/hrNg0TRCCsXPbJzcIq+NuzQhigunMWMJUA==", 774 | "dev": true, 775 | "requires": { 776 | "async": "^1.5.2", 777 | "mkdirp": "^0.5.1", 778 | "rimraf": "^2.5.2", 779 | "underscore-plus": "1.x" 780 | }, 781 | "dependencies": { 782 | "mkdirp": { 783 | "version": "0.5.1", 784 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 785 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 786 | "dev": true, 787 | "requires": { 788 | "minimist": "0.0.8" 789 | } 790 | } 791 | } 792 | }, 793 | "fs.realpath": { 794 | "version": "1.0.0", 795 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 796 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 797 | "dev": true 798 | }, 799 | "function-bind": { 800 | "version": "1.1.1", 801 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 802 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 803 | "dev": true 804 | }, 805 | "gaze": { 806 | "version": "0.3.4", 807 | "resolved": "https://registry.npmjs.org/gaze/-/gaze-0.3.4.tgz", 808 | "integrity": "sha1-X5S92gr+U7xxCWm81vKCVI1gwnk=", 809 | "dev": true, 810 | "requires": { 811 | "fileset": "~0.1.5", 812 | "minimatch": "~0.2.9" 813 | }, 814 | "dependencies": { 815 | "minimatch": { 816 | "version": "0.2.14", 817 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", 818 | "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", 819 | "dev": true, 820 | "requires": { 821 | "lru-cache": "2", 822 | "sigmund": "~1.0.0" 823 | } 824 | } 825 | } 826 | }, 827 | "generate-function": { 828 | "version": "2.3.1", 829 | "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", 830 | "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", 831 | "dev": true, 832 | "requires": { 833 | "is-property": "^1.0.2" 834 | } 835 | }, 836 | "generate-object-property": { 837 | "version": "1.2.0", 838 | "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", 839 | "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", 840 | "dev": true, 841 | "requires": { 842 | "is-property": "^1.0.0" 843 | } 844 | }, 845 | "get-stdin": { 846 | "version": "5.0.1", 847 | "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-5.0.1.tgz", 848 | "integrity": "sha1-Ei4WFZHiH/TFJTAwVpPyDmOTo5g=", 849 | "dev": true 850 | }, 851 | "glob": { 852 | "version": "7.1.4", 853 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", 854 | "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", 855 | "dev": true, 856 | "requires": { 857 | "fs.realpath": "^1.0.0", 858 | "inflight": "^1.0.4", 859 | "inherits": "2", 860 | "minimatch": "^3.0.4", 861 | "once": "^1.3.0", 862 | "path-is-absolute": "^1.0.0" 863 | } 864 | }, 865 | "globals": { 866 | "version": "9.18.0", 867 | "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", 868 | "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", 869 | "dev": true 870 | }, 871 | "graceful-fs": { 872 | "version": "4.1.15", 873 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", 874 | "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", 875 | "dev": true 876 | }, 877 | "has": { 878 | "version": "1.0.3", 879 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 880 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 881 | "dev": true, 882 | "requires": { 883 | "function-bind": "^1.1.1" 884 | } 885 | }, 886 | "has-ansi": { 887 | "version": "2.0.0", 888 | "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", 889 | "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", 890 | "dev": true, 891 | "requires": { 892 | "ansi-regex": "^2.0.0" 893 | } 894 | }, 895 | "has-symbols": { 896 | "version": "1.0.0", 897 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", 898 | "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", 899 | "dev": true 900 | }, 901 | "ignore": { 902 | "version": "3.3.10", 903 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", 904 | "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", 905 | "dev": true 906 | }, 907 | "imurmurhash": { 908 | "version": "0.1.4", 909 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", 910 | "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", 911 | "dev": true 912 | }, 913 | "inflight": { 914 | "version": "1.0.6", 915 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 916 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 917 | "dev": true, 918 | "requires": { 919 | "once": "^1.3.0", 920 | "wrappy": "1" 921 | } 922 | }, 923 | "inherits": { 924 | "version": "2.0.3", 925 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 926 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", 927 | "dev": true 928 | }, 929 | "inquirer": { 930 | "version": "0.12.0", 931 | "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz", 932 | "integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=", 933 | "dev": true, 934 | "requires": { 935 | "ansi-escapes": "^1.1.0", 936 | "ansi-regex": "^2.0.0", 937 | "chalk": "^1.0.0", 938 | "cli-cursor": "^1.0.1", 939 | "cli-width": "^2.0.0", 940 | "figures": "^1.3.5", 941 | "lodash": "^4.3.0", 942 | "readline2": "^1.0.1", 943 | "run-async": "^0.1.0", 944 | "rx-lite": "^3.1.2", 945 | "string-width": "^1.0.1", 946 | "strip-ansi": "^3.0.0", 947 | "through": "^2.3.6" 948 | } 949 | }, 950 | "interpret": { 951 | "version": "1.2.0", 952 | "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", 953 | "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==", 954 | "dev": true 955 | }, 956 | "is-arrayish": { 957 | "version": "0.2.1", 958 | "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", 959 | "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", 960 | "dev": true 961 | }, 962 | "is-callable": { 963 | "version": "1.1.4", 964 | "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", 965 | "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", 966 | "dev": true 967 | }, 968 | "is-date-object": { 969 | "version": "1.0.1", 970 | "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", 971 | "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", 972 | "dev": true 973 | }, 974 | "is-fullwidth-code-point": { 975 | "version": "1.0.0", 976 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", 977 | "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", 978 | "dev": true, 979 | "requires": { 980 | "number-is-nan": "^1.0.0" 981 | } 982 | }, 983 | "is-my-ip-valid": { 984 | "version": "1.0.0", 985 | "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz", 986 | "integrity": "sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==", 987 | "dev": true 988 | }, 989 | "is-my-json-valid": { 990 | "version": "2.20.0", 991 | "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.20.0.tgz", 992 | "integrity": "sha512-XTHBZSIIxNsIsZXg7XB5l8z/OBFosl1Wao4tXLpeC7eKU4Vm/kdop2azkPqULwnfGQjmeDIyey9g7afMMtdWAA==", 993 | "dev": true, 994 | "requires": { 995 | "generate-function": "^2.0.0", 996 | "generate-object-property": "^1.1.0", 997 | "is-my-ip-valid": "^1.0.0", 998 | "jsonpointer": "^4.0.0", 999 | "xtend": "^4.0.0" 1000 | } 1001 | }, 1002 | "is-property": { 1003 | "version": "1.0.2", 1004 | "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", 1005 | "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", 1006 | "dev": true 1007 | }, 1008 | "is-regex": { 1009 | "version": "1.0.4", 1010 | "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", 1011 | "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", 1012 | "dev": true, 1013 | "requires": { 1014 | "has": "^1.0.1" 1015 | } 1016 | }, 1017 | "is-resolvable": { 1018 | "version": "1.1.0", 1019 | "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", 1020 | "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", 1021 | "dev": true 1022 | }, 1023 | "is-symbol": { 1024 | "version": "1.0.2", 1025 | "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", 1026 | "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", 1027 | "dev": true, 1028 | "requires": { 1029 | "has-symbols": "^1.0.0" 1030 | } 1031 | }, 1032 | "isarray": { 1033 | "version": "1.0.0", 1034 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 1035 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", 1036 | "dev": true 1037 | }, 1038 | "jasmine-focused": { 1039 | "version": "1.0.7", 1040 | "resolved": "https://registry.npmjs.org/jasmine-focused/-/jasmine-focused-1.0.7.tgz", 1041 | "integrity": "sha1-uDx1fIAOaOHW78GjoaE/85/23NI=", 1042 | "dev": true, 1043 | "requires": { 1044 | "jasmine-node": "git+https://github.com/kevinsawicki/jasmine-node.git#81af4f953a2b7dfb5bde8331c05362a4b464c5ef", 1045 | "underscore-plus": "1.x", 1046 | "walkdir": "0.0.7" 1047 | } 1048 | }, 1049 | "jasmine-json": { 1050 | "version": "0.0.3", 1051 | "resolved": "https://registry.npmjs.org/jasmine-json/-/jasmine-json-0.0.3.tgz", 1052 | "integrity": "sha1-Xi6P1QqlhXAOjzWa9pawupZPg4c=", 1053 | "dev": true 1054 | }, 1055 | "jasmine-node": { 1056 | "version": "git+https://github.com/kevinsawicki/jasmine-node.git#81af4f953a2b7dfb5bde8331c05362a4b464c5ef", 1057 | "from": "git+https://github.com/kevinsawicki/jasmine-node.git#81af4f953a2b7dfb5bde8331c05362a4b464c5ef", 1058 | "dev": true, 1059 | "requires": { 1060 | "coffee-script": ">=1.0.1", 1061 | "coffeestack": ">=1 <2", 1062 | "gaze": "~0.3.2", 1063 | "jasmine-reporters": ">=0.2.0", 1064 | "mkdirp": "~0.3.5", 1065 | "requirejs": ">=0.27.1", 1066 | "underscore": ">= 1.3.1", 1067 | "walkdir": ">= 0.0.1" 1068 | } 1069 | }, 1070 | "jasmine-reporters": { 1071 | "version": "2.3.2", 1072 | "resolved": "https://registry.npmjs.org/jasmine-reporters/-/jasmine-reporters-2.3.2.tgz", 1073 | "integrity": "sha512-u/7AT9SkuZsUfFBLLzbErohTGNsEUCKaQbsVYnLFW1gEuL2DzmBL4n8v90uZsqIqlWvWUgian8J6yOt5Fyk/+A==", 1074 | "dev": true, 1075 | "requires": { 1076 | "mkdirp": "^0.5.1", 1077 | "xmldom": "^0.1.22" 1078 | }, 1079 | "dependencies": { 1080 | "mkdirp": { 1081 | "version": "0.5.1", 1082 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 1083 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 1084 | "dev": true, 1085 | "requires": { 1086 | "minimist": "0.0.8" 1087 | } 1088 | } 1089 | } 1090 | }, 1091 | "js-tokens": { 1092 | "version": "3.0.2", 1093 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", 1094 | "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", 1095 | "dev": true 1096 | }, 1097 | "js-yaml": { 1098 | "version": "3.13.1", 1099 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", 1100 | "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", 1101 | "dev": true, 1102 | "requires": { 1103 | "argparse": "^1.0.7", 1104 | "esprima": "^4.0.0" 1105 | } 1106 | }, 1107 | "json-parse-better-errors": { 1108 | "version": "1.0.2", 1109 | "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", 1110 | "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", 1111 | "dev": true 1112 | }, 1113 | "json-stable-stringify": { 1114 | "version": "1.0.1", 1115 | "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", 1116 | "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", 1117 | "dev": true, 1118 | "requires": { 1119 | "jsonify": "~0.0.0" 1120 | } 1121 | }, 1122 | "jsonify": { 1123 | "version": "0.0.0", 1124 | "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", 1125 | "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", 1126 | "dev": true 1127 | }, 1128 | "jsonpointer": { 1129 | "version": "4.0.1", 1130 | "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", 1131 | "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", 1132 | "dev": true 1133 | }, 1134 | "jsx-ast-utils": { 1135 | "version": "1.4.1", 1136 | "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz", 1137 | "integrity": "sha1-OGchPo3Xm/Ho8jAMDPwe+xgsDfE=", 1138 | "dev": true 1139 | }, 1140 | "levn": { 1141 | "version": "0.3.0", 1142 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", 1143 | "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", 1144 | "dev": true, 1145 | "requires": { 1146 | "prelude-ls": "~1.1.2", 1147 | "type-check": "~0.3.2" 1148 | } 1149 | }, 1150 | "load-json-file": { 1151 | "version": "4.0.0", 1152 | "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", 1153 | "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", 1154 | "dev": true, 1155 | "requires": { 1156 | "graceful-fs": "^4.1.2", 1157 | "parse-json": "^4.0.0", 1158 | "pify": "^3.0.0", 1159 | "strip-bom": "^3.0.0" 1160 | } 1161 | }, 1162 | "locate-path": { 1163 | "version": "2.0.0", 1164 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", 1165 | "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", 1166 | "dev": true, 1167 | "requires": { 1168 | "p-locate": "^2.0.0", 1169 | "path-exists": "^3.0.0" 1170 | } 1171 | }, 1172 | "lodash": { 1173 | "version": "4.17.11", 1174 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", 1175 | "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", 1176 | "dev": true 1177 | }, 1178 | "lodash.cond": { 1179 | "version": "4.5.2", 1180 | "resolved": "https://registry.npmjs.org/lodash.cond/-/lodash.cond-4.5.2.tgz", 1181 | "integrity": "sha1-9HGh2khr5g9quVXRcRVSPdHSVdU=", 1182 | "dev": true 1183 | }, 1184 | "lru-cache": { 1185 | "version": "2.7.3", 1186 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", 1187 | "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", 1188 | "dev": true 1189 | }, 1190 | "marked": { 1191 | "version": "0.6.2", 1192 | "resolved": "https://registry.npmjs.org/marked/-/marked-0.6.2.tgz", 1193 | "integrity": "sha512-LqxwVH3P/rqKX4EKGz7+c2G9r98WeM/SW34ybhgNGhUQNKtf1GmmSkJ6cDGJ/t6tiyae49qRkpyTw2B9HOrgUA==" 1194 | }, 1195 | "minimatch": { 1196 | "version": "3.0.4", 1197 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 1198 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 1199 | "dev": true, 1200 | "requires": { 1201 | "brace-expansion": "^1.1.7" 1202 | } 1203 | }, 1204 | "minimist": { 1205 | "version": "0.0.8", 1206 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 1207 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", 1208 | "dev": true 1209 | }, 1210 | "mkdirp": { 1211 | "version": "0.3.5", 1212 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", 1213 | "integrity": "sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc=", 1214 | "dev": true 1215 | }, 1216 | "ms": { 1217 | "version": "2.0.0", 1218 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 1219 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 1220 | "dev": true 1221 | }, 1222 | "mute-stream": { 1223 | "version": "0.0.5", 1224 | "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz", 1225 | "integrity": "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=", 1226 | "dev": true 1227 | }, 1228 | "natural-compare": { 1229 | "version": "1.4.0", 1230 | "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", 1231 | "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", 1232 | "dev": true 1233 | }, 1234 | "next-tick": { 1235 | "version": "1.0.0", 1236 | "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", 1237 | "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", 1238 | "dev": true 1239 | }, 1240 | "number-is-nan": { 1241 | "version": "1.0.1", 1242 | "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", 1243 | "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", 1244 | "dev": true 1245 | }, 1246 | "object-assign": { 1247 | "version": "4.1.1", 1248 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 1249 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", 1250 | "dev": true 1251 | }, 1252 | "object-keys": { 1253 | "version": "1.1.1", 1254 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", 1255 | "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", 1256 | "dev": true 1257 | }, 1258 | "object.assign": { 1259 | "version": "4.1.0", 1260 | "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", 1261 | "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", 1262 | "dev": true, 1263 | "requires": { 1264 | "define-properties": "^1.1.2", 1265 | "function-bind": "^1.1.1", 1266 | "has-symbols": "^1.0.0", 1267 | "object-keys": "^1.0.11" 1268 | } 1269 | }, 1270 | "once": { 1271 | "version": "1.4.0", 1272 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 1273 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 1274 | "dev": true, 1275 | "requires": { 1276 | "wrappy": "1" 1277 | } 1278 | }, 1279 | "onetime": { 1280 | "version": "1.1.0", 1281 | "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", 1282 | "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", 1283 | "dev": true 1284 | }, 1285 | "optionator": { 1286 | "version": "0.8.2", 1287 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", 1288 | "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", 1289 | "dev": true, 1290 | "requires": { 1291 | "deep-is": "~0.1.3", 1292 | "fast-levenshtein": "~2.0.4", 1293 | "levn": "~0.3.0", 1294 | "prelude-ls": "~1.1.2", 1295 | "type-check": "~0.3.2", 1296 | "wordwrap": "~1.0.0" 1297 | } 1298 | }, 1299 | "os-homedir": { 1300 | "version": "1.0.2", 1301 | "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", 1302 | "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", 1303 | "dev": true 1304 | }, 1305 | "p-limit": { 1306 | "version": "1.3.0", 1307 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", 1308 | "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", 1309 | "dev": true, 1310 | "requires": { 1311 | "p-try": "^1.0.0" 1312 | } 1313 | }, 1314 | "p-locate": { 1315 | "version": "2.0.0", 1316 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", 1317 | "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", 1318 | "dev": true, 1319 | "requires": { 1320 | "p-limit": "^1.1.0" 1321 | } 1322 | }, 1323 | "p-try": { 1324 | "version": "1.0.0", 1325 | "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", 1326 | "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", 1327 | "dev": true 1328 | }, 1329 | "parse-json": { 1330 | "version": "4.0.0", 1331 | "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", 1332 | "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", 1333 | "dev": true, 1334 | "requires": { 1335 | "error-ex": "^1.3.1", 1336 | "json-parse-better-errors": "^1.0.1" 1337 | } 1338 | }, 1339 | "path-exists": { 1340 | "version": "3.0.0", 1341 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", 1342 | "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", 1343 | "dev": true 1344 | }, 1345 | "path-is-absolute": { 1346 | "version": "1.0.1", 1347 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 1348 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 1349 | "dev": true 1350 | }, 1351 | "path-is-inside": { 1352 | "version": "1.0.2", 1353 | "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", 1354 | "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", 1355 | "dev": true 1356 | }, 1357 | "path-parse": { 1358 | "version": "1.0.6", 1359 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", 1360 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", 1361 | "dev": true 1362 | }, 1363 | "pify": { 1364 | "version": "3.0.0", 1365 | "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", 1366 | "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", 1367 | "dev": true 1368 | }, 1369 | "pinkie": { 1370 | "version": "2.0.4", 1371 | "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", 1372 | "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", 1373 | "dev": true 1374 | }, 1375 | "pinkie-promise": { 1376 | "version": "2.0.1", 1377 | "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", 1378 | "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", 1379 | "dev": true, 1380 | "requires": { 1381 | "pinkie": "^2.0.0" 1382 | } 1383 | }, 1384 | "pkg-conf": { 1385 | "version": "2.1.0", 1386 | "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-2.1.0.tgz", 1387 | "integrity": "sha1-ISZRTKbyq/69FoWW3xi6V4Z/AFg=", 1388 | "dev": true, 1389 | "requires": { 1390 | "find-up": "^2.0.0", 1391 | "load-json-file": "^4.0.0" 1392 | } 1393 | }, 1394 | "pkg-config": { 1395 | "version": "1.1.1", 1396 | "resolved": "https://registry.npmjs.org/pkg-config/-/pkg-config-1.1.1.tgz", 1397 | "integrity": "sha1-VX7yLXPaPIg3EHdmxS6tq94pj+Q=", 1398 | "dev": true, 1399 | "requires": { 1400 | "debug-log": "^1.0.0", 1401 | "find-root": "^1.0.0", 1402 | "xtend": "^4.0.1" 1403 | } 1404 | }, 1405 | "pkg-dir": { 1406 | "version": "2.0.0", 1407 | "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", 1408 | "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", 1409 | "dev": true, 1410 | "requires": { 1411 | "find-up": "^2.1.0" 1412 | } 1413 | }, 1414 | "pkg-up": { 1415 | "version": "1.0.0", 1416 | "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-1.0.0.tgz", 1417 | "integrity": "sha1-Pgj7RhUlxEIWJKM7n35tCvWwWiY=", 1418 | "dev": true, 1419 | "requires": { 1420 | "find-up": "^1.0.0" 1421 | }, 1422 | "dependencies": { 1423 | "find-up": { 1424 | "version": "1.1.2", 1425 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", 1426 | "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", 1427 | "dev": true, 1428 | "requires": { 1429 | "path-exists": "^2.0.0", 1430 | "pinkie-promise": "^2.0.0" 1431 | } 1432 | }, 1433 | "path-exists": { 1434 | "version": "2.1.0", 1435 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", 1436 | "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", 1437 | "dev": true, 1438 | "requires": { 1439 | "pinkie-promise": "^2.0.0" 1440 | } 1441 | } 1442 | } 1443 | }, 1444 | "pluralize": { 1445 | "version": "1.2.1", 1446 | "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz", 1447 | "integrity": "sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU=", 1448 | "dev": true 1449 | }, 1450 | "prelude-ls": { 1451 | "version": "1.1.2", 1452 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", 1453 | "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", 1454 | "dev": true 1455 | }, 1456 | "process-nextick-args": { 1457 | "version": "2.0.0", 1458 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", 1459 | "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", 1460 | "dev": true 1461 | }, 1462 | "progress": { 1463 | "version": "1.1.8", 1464 | "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", 1465 | "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", 1466 | "dev": true 1467 | }, 1468 | "readable-stream": { 1469 | "version": "2.3.6", 1470 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", 1471 | "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", 1472 | "dev": true, 1473 | "requires": { 1474 | "core-util-is": "~1.0.0", 1475 | "inherits": "~2.0.3", 1476 | "isarray": "~1.0.0", 1477 | "process-nextick-args": "~2.0.0", 1478 | "safe-buffer": "~5.1.1", 1479 | "string_decoder": "~1.1.1", 1480 | "util-deprecate": "~1.0.1" 1481 | } 1482 | }, 1483 | "readline2": { 1484 | "version": "1.0.1", 1485 | "resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz", 1486 | "integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=", 1487 | "dev": true, 1488 | "requires": { 1489 | "code-point-at": "^1.0.0", 1490 | "is-fullwidth-code-point": "^1.0.0", 1491 | "mute-stream": "0.0.5" 1492 | } 1493 | }, 1494 | "rechoir": { 1495 | "version": "0.6.2", 1496 | "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", 1497 | "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", 1498 | "dev": true, 1499 | "requires": { 1500 | "resolve": "^1.1.6" 1501 | } 1502 | }, 1503 | "require-uncached": { 1504 | "version": "1.0.3", 1505 | "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", 1506 | "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", 1507 | "dev": true, 1508 | "requires": { 1509 | "caller-path": "^0.1.0", 1510 | "resolve-from": "^1.0.0" 1511 | } 1512 | }, 1513 | "requirejs": { 1514 | "version": "2.3.6", 1515 | "resolved": "https://registry.npmjs.org/requirejs/-/requirejs-2.3.6.tgz", 1516 | "integrity": "sha512-ipEzlWQe6RK3jkzikgCupiTbTvm4S0/CAU5GlgptkN5SO6F3u0UD0K18wy6ErDqiCyP4J4YYe1HuAShvsxePLg==", 1517 | "dev": true 1518 | }, 1519 | "resolve": { 1520 | "version": "1.11.0", 1521 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.0.tgz", 1522 | "integrity": "sha512-WL2pBDjqT6pGUNSUzMw00o4T7If+z4H2x3Gz893WoUQ5KW8Vr9txp00ykiP16VBaZF5+j/OcXJHZ9+PCvdiDKw==", 1523 | "dev": true, 1524 | "requires": { 1525 | "path-parse": "^1.0.6" 1526 | } 1527 | }, 1528 | "resolve-from": { 1529 | "version": "1.0.1", 1530 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", 1531 | "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", 1532 | "dev": true 1533 | }, 1534 | "restore-cursor": { 1535 | "version": "1.0.1", 1536 | "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", 1537 | "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", 1538 | "dev": true, 1539 | "requires": { 1540 | "exit-hook": "^1.0.0", 1541 | "onetime": "^1.0.0" 1542 | } 1543 | }, 1544 | "rimraf": { 1545 | "version": "2.6.3", 1546 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", 1547 | "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", 1548 | "dev": true, 1549 | "requires": { 1550 | "glob": "^7.1.3" 1551 | } 1552 | }, 1553 | "run-async": { 1554 | "version": "0.1.0", 1555 | "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz", 1556 | "integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=", 1557 | "dev": true, 1558 | "requires": { 1559 | "once": "^1.3.0" 1560 | } 1561 | }, 1562 | "run-parallel": { 1563 | "version": "1.1.9", 1564 | "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", 1565 | "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", 1566 | "dev": true 1567 | }, 1568 | "rx-lite": { 1569 | "version": "3.1.2", 1570 | "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz", 1571 | "integrity": "sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI=", 1572 | "dev": true 1573 | }, 1574 | "safe-buffer": { 1575 | "version": "5.1.2", 1576 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 1577 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", 1578 | "dev": true 1579 | }, 1580 | "semver": { 1581 | "version": "5.3.0", 1582 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", 1583 | "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", 1584 | "dev": true 1585 | }, 1586 | "shelljs": { 1587 | "version": "0.7.8", 1588 | "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz", 1589 | "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=", 1590 | "dev": true, 1591 | "requires": { 1592 | "glob": "^7.0.0", 1593 | "interpret": "^1.0.0", 1594 | "rechoir": "^0.6.2" 1595 | } 1596 | }, 1597 | "sigmund": { 1598 | "version": "1.0.1", 1599 | "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", 1600 | "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", 1601 | "dev": true 1602 | }, 1603 | "slice-ansi": { 1604 | "version": "0.0.4", 1605 | "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", 1606 | "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", 1607 | "dev": true 1608 | }, 1609 | "source-map": { 1610 | "version": "0.1.43", 1611 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", 1612 | "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", 1613 | "dev": true, 1614 | "requires": { 1615 | "amdefine": ">=0.0.4" 1616 | } 1617 | }, 1618 | "sprintf-js": { 1619 | "version": "1.0.3", 1620 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 1621 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 1622 | "dev": true 1623 | }, 1624 | "standard": { 1625 | "version": "10.0.3", 1626 | "resolved": "https://registry.npmjs.org/standard/-/standard-10.0.3.tgz", 1627 | "integrity": "sha512-JURZ+85ExKLQULckDFijdX5WHzN6RC7fgiZNSV4jFQVo+3tPoQGHyBrGekye/yf0aOfb4210EM5qPNlc2cRh4w==", 1628 | "dev": true, 1629 | "requires": { 1630 | "eslint": "~3.19.0", 1631 | "eslint-config-standard": "10.2.1", 1632 | "eslint-config-standard-jsx": "4.0.2", 1633 | "eslint-plugin-import": "~2.2.0", 1634 | "eslint-plugin-node": "~4.2.2", 1635 | "eslint-plugin-promise": "~3.5.0", 1636 | "eslint-plugin-react": "~6.10.0", 1637 | "eslint-plugin-standard": "~3.0.1", 1638 | "standard-engine": "~7.0.0" 1639 | } 1640 | }, 1641 | "standard-engine": { 1642 | "version": "7.0.0", 1643 | "resolved": "https://registry.npmjs.org/standard-engine/-/standard-engine-7.0.0.tgz", 1644 | "integrity": "sha1-67d7nI/CyBZf+jU72Rug3/Qa9pA=", 1645 | "dev": true, 1646 | "requires": { 1647 | "deglob": "^2.1.0", 1648 | "get-stdin": "^5.0.1", 1649 | "minimist": "^1.1.0", 1650 | "pkg-conf": "^2.0.0" 1651 | }, 1652 | "dependencies": { 1653 | "minimist": { 1654 | "version": "1.2.0", 1655 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", 1656 | "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", 1657 | "dev": true 1658 | } 1659 | } 1660 | }, 1661 | "string-width": { 1662 | "version": "1.0.2", 1663 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", 1664 | "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", 1665 | "dev": true, 1666 | "requires": { 1667 | "code-point-at": "^1.0.0", 1668 | "is-fullwidth-code-point": "^1.0.0", 1669 | "strip-ansi": "^3.0.0" 1670 | } 1671 | }, 1672 | "string_decoder": { 1673 | "version": "1.1.1", 1674 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 1675 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 1676 | "dev": true, 1677 | "requires": { 1678 | "safe-buffer": "~5.1.0" 1679 | } 1680 | }, 1681 | "strip-ansi": { 1682 | "version": "3.0.1", 1683 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", 1684 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", 1685 | "dev": true, 1686 | "requires": { 1687 | "ansi-regex": "^2.0.0" 1688 | } 1689 | }, 1690 | "strip-bom": { 1691 | "version": "3.0.0", 1692 | "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", 1693 | "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", 1694 | "dev": true 1695 | }, 1696 | "strip-json-comments": { 1697 | "version": "2.0.1", 1698 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 1699 | "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", 1700 | "dev": true 1701 | }, 1702 | "supports-color": { 1703 | "version": "2.0.0", 1704 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", 1705 | "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", 1706 | "dev": true 1707 | }, 1708 | "table": { 1709 | "version": "3.8.3", 1710 | "resolved": "https://registry.npmjs.org/table/-/table-3.8.3.tgz", 1711 | "integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=", 1712 | "dev": true, 1713 | "requires": { 1714 | "ajv": "^4.7.0", 1715 | "ajv-keywords": "^1.0.0", 1716 | "chalk": "^1.1.1", 1717 | "lodash": "^4.0.0", 1718 | "slice-ansi": "0.0.4", 1719 | "string-width": "^2.0.0" 1720 | }, 1721 | "dependencies": { 1722 | "ansi-regex": { 1723 | "version": "3.0.0", 1724 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", 1725 | "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", 1726 | "dev": true 1727 | }, 1728 | "is-fullwidth-code-point": { 1729 | "version": "2.0.0", 1730 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", 1731 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", 1732 | "dev": true 1733 | }, 1734 | "string-width": { 1735 | "version": "2.1.1", 1736 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", 1737 | "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", 1738 | "dev": true, 1739 | "requires": { 1740 | "is-fullwidth-code-point": "^2.0.0", 1741 | "strip-ansi": "^4.0.0" 1742 | } 1743 | }, 1744 | "strip-ansi": { 1745 | "version": "4.0.0", 1746 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", 1747 | "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", 1748 | "dev": true, 1749 | "requires": { 1750 | "ansi-regex": "^3.0.0" 1751 | } 1752 | } 1753 | } 1754 | }, 1755 | "text-table": { 1756 | "version": "0.2.0", 1757 | "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", 1758 | "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", 1759 | "dev": true 1760 | }, 1761 | "through": { 1762 | "version": "2.3.8", 1763 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", 1764 | "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", 1765 | "dev": true 1766 | }, 1767 | "type-check": { 1768 | "version": "0.3.2", 1769 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", 1770 | "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", 1771 | "dev": true, 1772 | "requires": { 1773 | "prelude-ls": "~1.1.2" 1774 | } 1775 | }, 1776 | "typedarray": { 1777 | "version": "0.0.6", 1778 | "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", 1779 | "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", 1780 | "dev": true 1781 | }, 1782 | "underscore": { 1783 | "version": "1.9.1", 1784 | "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz", 1785 | "integrity": "sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg==", 1786 | "dev": true 1787 | }, 1788 | "underscore-plus": { 1789 | "version": "1.7.0", 1790 | "resolved": "https://registry.npmjs.org/underscore-plus/-/underscore-plus-1.7.0.tgz", 1791 | "integrity": "sha512-A3BEzkeicFLnr+U/Q3EyWwJAQPbA19mtZZ4h+lLq3ttm9kn8WC4R3YpuJZEXmWdLjYP47Zc8aLZm9kwdv+zzvA==", 1792 | "dev": true, 1793 | "requires": { 1794 | "underscore": "^1.9.1" 1795 | } 1796 | }, 1797 | "uniq": { 1798 | "version": "1.0.1", 1799 | "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", 1800 | "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", 1801 | "dev": true 1802 | }, 1803 | "user-home": { 1804 | "version": "2.0.0", 1805 | "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz", 1806 | "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=", 1807 | "dev": true, 1808 | "requires": { 1809 | "os-homedir": "^1.0.0" 1810 | } 1811 | }, 1812 | "util-deprecate": { 1813 | "version": "1.0.2", 1814 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 1815 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", 1816 | "dev": true 1817 | }, 1818 | "walkdir": { 1819 | "version": "0.0.7", 1820 | "resolved": "https://registry.npmjs.org/walkdir/-/walkdir-0.0.7.tgz", 1821 | "integrity": "sha1-BNoCcKh6d4VAFzzb8KLbSZqNnik=", 1822 | "dev": true 1823 | }, 1824 | "wordwrap": { 1825 | "version": "1.0.0", 1826 | "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", 1827 | "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", 1828 | "dev": true 1829 | }, 1830 | "wrappy": { 1831 | "version": "1.0.2", 1832 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1833 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 1834 | "dev": true 1835 | }, 1836 | "write": { 1837 | "version": "0.2.1", 1838 | "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", 1839 | "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", 1840 | "dev": true, 1841 | "requires": { 1842 | "mkdirp": "^0.5.1" 1843 | }, 1844 | "dependencies": { 1845 | "mkdirp": { 1846 | "version": "0.5.1", 1847 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 1848 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 1849 | "dev": true, 1850 | "requires": { 1851 | "minimist": "0.0.8" 1852 | } 1853 | } 1854 | } 1855 | }, 1856 | "xmldom": { 1857 | "version": "0.1.27", 1858 | "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz", 1859 | "integrity": "sha1-1QH5ezvbQDr4757MIFcxh6rawOk=", 1860 | "dev": true 1861 | }, 1862 | "xtend": { 1863 | "version": "4.0.1", 1864 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", 1865 | "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", 1866 | "dev": true 1867 | } 1868 | } 1869 | } 1870 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "atomdoc", 3 | "version": "1.2.0", 4 | "description": "An atomdoc parser", 5 | "main": "./src/atomdoc.js", 6 | "scripts": { 7 | "lint": "standard src/*.js spec/*.js", 8 | "prepublish": "npm run lint", 9 | "test": "npm run lint && jasmine-focused --captureExceptions spec/" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/atom/atomdoc.git" 14 | }, 15 | "licenses": [ 16 | { 17 | "type": "MIT", 18 | "url": "http://github.com/atom/atomdoc/raw/master/LICENSE.md" 19 | } 20 | ], 21 | "bugs": { 22 | "url": "https://github.com/atom/atomdoc/issues" 23 | }, 24 | "homepage": "http://atom.github.io/atomdoc", 25 | "dependencies": { 26 | "marked": "^0.6.2" 27 | }, 28 | "devDependencies": { 29 | "dedent": "^0.7.0", 30 | "jasmine-focused": "1.x", 31 | "jasmine-json": "~0.0", 32 | "standard": "^10.0.3" 33 | }, 34 | "standard": { 35 | "env": { 36 | "atomtest": true, 37 | "browser": true, 38 | "jasmine": true, 39 | "node": true 40 | }, 41 | "globals": [ 42 | "atom" 43 | ] 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /spec/parser-spec.js: -------------------------------------------------------------------------------- 1 | require('jasmine-json') 2 | const dedent = require('dedent') 3 | const {parse} = require('../src/parser') 4 | 5 | describe('parser', function () { 6 | describe('summary and description', function () { 7 | it('parses a simple one liner', function () { 8 | const str = 'Public: Batch multiple operations as a single undo/redo step.' 9 | const doc = parse(str) 10 | 11 | expect(doc.visibility).toBe('Public') 12 | expect(doc.summary).toBe('Batch multiple operations as a single undo/redo step.') 13 | expect(doc.description).toBe('Batch multiple operations as a single undo/redo step.') 14 | expect(doc.returnValue).not.toBeDefined() 15 | expect(doc.examples).not.toBeDefined() 16 | expect(doc.delegation).not.toBeDefined() 17 | }) 18 | 19 | it('parses the description properly', function () { 20 | const str = 21 | dedent`\ 22 | Public: Batch multiple operations as a single undo/redo step. 23 | 24 | Here is some description.\ 25 | ` 26 | const doc = parse(str) 27 | 28 | expect(doc.visibility).toBe('Public') 29 | expect(doc.summary).toBe('Batch multiple operations as a single undo/redo step.') 30 | expect(doc.description).toBe( 31 | dedent`\ 32 | Batch multiple operations as a single undo/redo step. 33 | 34 | Here is some description.\ 35 | ` 36 | ) 37 | expect(doc.returnValue).not.toBeDefined() 38 | expect(doc.examples).not.toBeDefined() 39 | expect(doc.delegation).not.toBeDefined() 40 | }) 41 | 42 | it('parses the description when there are code blocks', function () { 43 | const str = 44 | dedent`\ 45 | Public: Batch multiple operations as a single undo/redo step. 46 | 47 | \`\`\`coffee 48 | a = 23 49 | \`\`\` 50 | 51 | Here is some description. 52 | 53 | \`\`\` 54 | for a in [1, 2, 3] 55 | \`\`\`\ 56 | ` 57 | const doc = parse(str) 58 | 59 | expect(doc.visibility).toBe('Public') 60 | expect(doc.summary).toBe('Batch multiple operations as a single undo/redo step.') 61 | expect(doc.description).toBe( 62 | dedent`\ 63 | Batch multiple operations as a single undo/redo step. 64 | 65 | \`\`\`coffee 66 | a = 23 67 | \`\`\` 68 | 69 | Here is some description. 70 | 71 | \`\`\` 72 | for a in [1, 2, 3] 73 | \`\`\`\ 74 | ` 75 | ) 76 | }) 77 | 78 | it('parses the description when there are headings', function () { 79 | const str = 80 | dedent`\ 81 | Public: Batch multiple operations as a single undo/redo step. 82 | 83 | 84 | ## Ok, computer 85 | 86 | Do your thing\ 87 | ` 88 | const doc = parse(str) 89 | 90 | expect(doc.visibility).toBe('Public') 91 | expect(doc.summary).toBe('Batch multiple operations as a single undo/redo step.') 92 | expect(doc.description).toBe( 93 | dedent`\ 94 | Batch multiple operations as a single undo/redo step. 95 | 96 | ## Ok, computer 97 | 98 | Do your thing\ 99 | ` 100 | ) 101 | }) 102 | 103 | it('parses the description when there are blockquotes', function () { 104 | const str = 105 | dedent`\ 106 | Public: Batch multiple operations as a single undo/redo step. 107 | 108 | 109 | > this is a quote 110 | > another one 111 | 112 | Do your thing 113 | 114 | > a second block\ 115 | ` 116 | const doc = parse(str) 117 | 118 | expect(doc.visibility).toBe('Public') 119 | expect(doc.summary).toBe('Batch multiple operations as a single undo/redo step.') 120 | expect(doc.description).toBe( 121 | dedent`\ 122 | Batch multiple operations as a single undo/redo step. 123 | 124 | > this is a quote 125 | > another one 126 | 127 | Do your thing 128 | 129 | > a second block\ 130 | ` 131 | ) 132 | }) 133 | 134 | describe('when there are lists in the description', function () { 135 | it('parses the description when there are lists that are not arg lists', function () { 136 | const str = 137 | dedent`\ 138 | Public: Batch multiple operations as a single undo/redo step. 139 | 140 | * one 141 | * two 142 | \`\`\`coffee 143 | ok = 1 144 | \`\`\` 145 | * This one has a blockquote, wtf?! 146 | > something 147 | > fuuu 148 | * someotherArg 149 | 150 | blah 151 | 152 | * one 153 | 1. two 154 | 1. three 155 | * four 156 | 1. five 157 | * six 158 | 159 | Painful.\ 160 | ` 161 | const doc = parse(str) 162 | 163 | expect(doc.visibility).toBe('Public') 164 | expect(doc.summary).toBe('Batch multiple operations as a single undo/redo step.') 165 | expect(doc.description).toBe( 166 | dedent`\ 167 | Batch multiple operations as a single undo/redo step. 168 | 169 | * one 170 | * two 171 | \`\`\`coffee 172 | ok = 1 173 | \`\`\` 174 | * This one has a blockquote, wtf?! 175 | > something 176 | > fuuu 177 | * someotherArg 178 | 179 | blah 180 | 181 | * one 182 | 1. two 183 | 1. three 184 | * four 185 | 1. five 186 | * six 187 | 188 | Painful.\ 189 | ` 190 | ) 191 | }) 192 | 193 | it('description lists do not interfere with the arguments', function () { 194 | const str = 195 | dedent`\ 196 | Public: Batch multiple operations as a single undo/redo step. 197 | 198 | * one 199 | * two 200 | 201 | Rainbows 202 | 203 | * \`fn\` A {Function} to call inside the transaction.\ 204 | ` 205 | const doc = parse(str) 206 | 207 | expect(doc.visibility).toBe('Public') 208 | expect(doc.summary).toBe('Batch multiple operations as a single undo/redo step.') 209 | expect(doc.description).toBe( 210 | dedent`\ 211 | Batch multiple operations as a single undo/redo step. 212 | 213 | * one 214 | * two 215 | 216 | Rainbows\ 217 | ` 218 | ) 219 | expect(doc.arguments).toEqualJson([{ 220 | name: 'fn', 221 | description: 'A {Function} to call inside the transaction.', 222 | type: 'Function', 223 | isOptional: false 224 | } 225 | ]) 226 | }) 227 | }) 228 | 229 | describe('with different visibilities', function () { 230 | it('parses a public visibility', function () { 231 | const doc = parse('Public: Batch multiple operations as a single undo/redo step.') 232 | expect(doc.visibility).toBe('Public') 233 | expect(doc.isPublic()).toBe(true) 234 | }) 235 | 236 | it('parses Essential visibility', function () { 237 | const doc = parse('Essential: Batch multiple operations as a single undo/redo step.') 238 | expect(doc.visibility).toBe('Essential') 239 | expect(doc.isPublic()).toBe(true) 240 | }) 241 | 242 | it('parses a private visibility', function () { 243 | const doc = parse('Private: Batch multiple operations as a single undo/redo step.') 244 | expect(doc.visibility).toBe('Private') 245 | expect(doc.isPublic()).toBe(false) 246 | }) 247 | 248 | it('parses an internal visibility', function () { 249 | const doc = parse('Internal: Batch multiple operations as a single undo/redo step.') 250 | expect(doc.visibility).toBe('Internal') 251 | expect(doc.isPublic()).toBe(false) 252 | }) 253 | 254 | it('parses no visibility', function () { 255 | const doc = parse('Batch multiple operations as a single undo/redo step.') 256 | expect(doc.visibility).toBe('Private') 257 | expect(doc.isPublic()).toBe(false) 258 | }) 259 | }) 260 | }) 261 | 262 | describe('arguments', function () { 263 | it('parses single level arguments', function () { 264 | const str = 265 | dedent`\ 266 | Public: Batch multiple operations as a single undo/redo step. 267 | 268 | * \`fn\` A {Function} to call inside the transaction.\ 269 | ` 270 | const doc = parse(str) 271 | 272 | expect(doc.arguments).toEqualJson([{ 273 | name: 'fn', 274 | description: 'A {Function} to call inside the transaction.', 275 | type: 'Function', 276 | isOptional: false 277 | } 278 | ]) 279 | }) 280 | 281 | it('parses optional arguments', function () { 282 | const str = 283 | dedent`\ 284 | Public: Batch multiple operations as a single undo/redo step. 285 | 286 | * \`index\` {Int} index 287 | * \`fn\` (optional) A {Function} to call inside the transaction.\ 288 | ` 289 | const doc = parse(str) 290 | 291 | expect(doc.arguments).toEqualJson([{ 292 | name: 'index', 293 | description: '{Int} index', 294 | type: 'Int', 295 | isOptional: false 296 | }, { 297 | name: 'fn', 298 | description: 'A {Function} to call inside the transaction.', 299 | type: 'Function', 300 | isOptional: true 301 | }]) 302 | }) 303 | 304 | it('parses names with all the accepted characters', function () { 305 | const str = 306 | dedent`\ 307 | Public: Batch multiple operations as a single undo/redo step. 308 | 309 | * \`oneTWO3.4-5_6\` A {Function} to call inside the transaction.\ 310 | ` 311 | const doc = parse(str) 312 | 313 | expect(doc.arguments[0].name).toEqual('oneTWO3.4-5_6') 314 | }) 315 | 316 | it('parses arguments with code blocks', function () { 317 | const str = 318 | dedent`\ 319 | Public: Batch multiple operations as a single undo/redo step. 320 | 321 | * \`options\` {Object} options hash 322 | \`\`\`js 323 | a = 1 324 | \`\`\` 325 | * \`something\` {Object} something\ 326 | ` 327 | const doc = parse(str) 328 | 329 | expect(doc.arguments).toEqualJson([{ 330 | name: 'options', 331 | description: '{Object} options hash\n```js\na = 1\n```', 332 | type: 'Object', 333 | isOptional: false 334 | }, { 335 | name: 'something', 336 | description: '{Object} something', 337 | type: 'Object', 338 | isOptional: false 339 | }]) 340 | }) 341 | 342 | it('parses non-argument sublists as description', function () { 343 | const str = 344 | dedent`\ 345 | Public: Create a marker with the given range. 346 | 347 | * \`range\` {Range} 348 | * \`properties\` A hash of key-value pairs 349 | * __never__: The marker is never marked as invalid. 350 | * __surround__: The marker is invalidated by changes that completely surround it. 351 | 352 | Returns a {Marker}\ 353 | ` 354 | const doc = parse(str) 355 | 356 | expect(doc.arguments).toEqualJson([{ 357 | name: 'range', 358 | description: '{Range}', 359 | type: 'Range', 360 | isOptional: false 361 | }, { 362 | name: 'properties', 363 | description: 364 | dedent`\ 365 | A hash of key-value pairs 366 | * __never__: The marker is never marked as invalid. 367 | * __surround__: The marker is invalidated by changes that completely surround it.\ 368 | `, 369 | type: null, 370 | isOptional: false 371 | }]) 372 | }) 373 | 374 | it('handles nested arguments', function () { 375 | const str = 376 | dedent`\ 377 | Public: Batch multiple operations as a single undo/redo step. 378 | 379 | * \`1\` one 380 | * \`1.1\` two 381 | * \`1.2\` three 382 | * \`1.2.1\` four 383 | * \`1.3\` five 384 | * \`2\` six\ 385 | ` 386 | const doc = parse(str) 387 | 388 | expect(doc.arguments).toEqualJson([{ 389 | name: '1', 390 | description: 'one', 391 | type: null, 392 | isOptional: false, 393 | children: [{ 394 | name: '1.1', 395 | description: 'two', 396 | type: null, 397 | isOptional: false 398 | }, { 399 | name: '1.2', 400 | description: 'three', 401 | type: null, 402 | isOptional: false, 403 | children: [{ 404 | name: '1.2.1', 405 | description: 'four', 406 | type: null, 407 | isOptional: false 408 | }] 409 | }, { 410 | name: '1.3', 411 | description: 'five', 412 | type: null, 413 | isOptional: false 414 | }] 415 | }, { 416 | name: '2', 417 | description: 'six', 418 | type: null, 419 | isOptional: false 420 | }]) 421 | }) 422 | 423 | it("parses out an 'extra' description after the arguments", function () { 424 | const str = 425 | dedent`\ 426 | Public: Invoke the given callback when all marker \`::onDidChange\` 427 | observers have been notified following a change to the buffer. 428 | 429 | * \`callback\` {Function} to be called after markers are updated. 430 | 431 | The order of events following a buffer change is as follows: 432 | 433 | * The text of the buffer is changed 434 | * All markers are updated accordingly, but their \`::onDidChange\` observers 435 | are not notified. 436 | 437 | This is some more extra description 438 | 439 | Returns a {Disposable} on which \`.dispose()\` can be called to unsubscribe.\ 440 | ` 441 | const doc = parse(str) 442 | expect(doc.description).toEqualJson( 443 | dedent`\ 444 | Invoke the given callback when all marker \`::onDidChange\` 445 | observers have been notified following a change to the buffer. 446 | 447 | The order of events following a buffer change is as follows: 448 | 449 | * The text of the buffer is changed 450 | * All markers are updated accordingly, but their \`::onDidChange\` observers 451 | are not notified. 452 | 453 | This is some more extra description\ 454 | ` 455 | ) 456 | expect(doc.arguments).toEqualJson([{ 457 | 'name': 'callback', 458 | 'description': '{Function} to be called after markers are updated.', 459 | 'type': 'Function', 460 | 'isOptional': false 461 | } 462 | ]) 463 | }) 464 | 465 | describe('when there is an "Arguments" header', function () { 466 | it('parses arguments without a description', function () { 467 | const str = 468 | dedent`\ 469 | Public: Batch multiple operations as a single undo/redo step. 470 | 471 | ## Arguments 472 | 473 | * \`something\` A {Bool}\ 474 | ` 475 | const doc = parse(str) 476 | expect(doc.arguments).toEqualJson([{ 477 | name: 'something', 478 | description: 'A {Bool}', 479 | type: 'Bool', 480 | isOptional: false 481 | } 482 | ]) 483 | }) 484 | 485 | it('parses arguments with a description by ignoring the description', function () { 486 | const str = 487 | dedent`\ 488 | Public: Batch multiple operations as a single undo/redo step. 489 | 490 | ## Arguments 491 | 492 | This should be ignored 493 | 494 | * \`something\` A {Bool}\ 495 | ` 496 | const doc = parse(str) 497 | expect(doc.arguments).toEqualJson([{ 498 | name: 'something', 499 | description: 'A {Bool}', 500 | type: 'Bool', 501 | isOptional: false 502 | } 503 | ]) 504 | }) 505 | }) 506 | 507 | describe('when there are multiple "Arguments" headers describing different forms of the method', () => 508 | it('parses arguments without a description', function () { 509 | const str = 510 | dedent`\ 511 | Public: Batch multiple operations as a single undo/redo step. 512 | 513 | ## Arguments: Form one 514 | 515 | * \`something\` A {Bool} 516 | 517 | ## Arguments: Form two 518 | 519 | Some description here. 520 | 521 | * \`somethingElse\` A {String}\ 522 | ` 523 | const doc = parse(str) 524 | expect(doc.arguments).toBeUndefined() 525 | expect(doc.titledArguments).toEqualJson([{ 526 | title: 'Form one', 527 | description: '', 528 | arguments: [{ 529 | name: 'something', 530 | description: 'A {Bool}', 531 | type: 'Bool', 532 | isOptional: false 533 | } 534 | ] 535 | }, { 536 | title: 'Form two', 537 | description: 'Some description here.', 538 | arguments: [{ 539 | name: 'somethingElse', 540 | description: 'A {String}', 541 | type: 'String', 542 | isOptional: false 543 | } 544 | ] 545 | }]) 546 | }) 547 | ) 548 | }) 549 | 550 | describe('events section', function () { 551 | it('parses events with nested arguments', function () { 552 | const str = 553 | dedent`\ 554 | Public: Batch multiple operations as a single undo/redo step. 555 | 556 | * \`something\` A {Bool} 557 | 558 | ## Events 559 | 560 | ### contents-modified 561 | 562 | Essential: Fired when this thing happens. 563 | 564 | * \`options\` options hash 565 | * \`anOption\` true to do something\ 566 | ` 567 | const doc = parse(str) 568 | expect(doc.events).toEqualJson([{ 569 | name: 'contents-modified', 570 | summary: 'Fired when this thing happens.', 571 | description: 'Fired when this thing happens.', 572 | visibility: 'Essential', 573 | arguments: [{ 574 | name: 'options', 575 | description: 'options hash', 576 | type: null, 577 | isOptional: false, 578 | children: [{ 579 | name: 'anOption', 580 | description: 'true to do something', 581 | type: null, 582 | isOptional: false 583 | } 584 | ] 585 | } 586 | ] 587 | } 588 | ]) 589 | }) 590 | 591 | it('parses events with a description', function () { 592 | const str = 593 | dedent`\ 594 | Public: Batch multiple operations as a single undo/redo step. 595 | 596 | ## Arguments 597 | 598 | Some description 599 | 600 | * \`something\` A {Bool} 601 | 602 | ## Events 603 | 604 | Events do this and that and this too. 605 | 606 | ### contents-modified 607 | 608 | Public: Fired when this thing happens. 609 | 610 | This is a body of the thing 611 | 612 | * \`options\` options hash\ 613 | ` 614 | const doc = parse(str) 615 | expect(doc.events).toEqualJson([{ 616 | name: 'contents-modified', 617 | summary: 'Fired when this thing happens.', 618 | description: 'Fired when this thing happens.\n\nThis is a body of the thing', 619 | visibility: 'Public', 620 | arguments: [{ 621 | name: 'options', 622 | description: 'options hash', 623 | type: null, 624 | isOptional: false 625 | } 626 | ] 627 | } 628 | ]) 629 | }) 630 | 631 | describe('when there are no options specified', () => 632 | it('parses multiple events with no options', function () { 633 | const str = 634 | dedent`\ 635 | Public: Batch multiple operations as a single undo/redo step. 636 | 637 | ## Events 638 | 639 | ### contents-modified 640 | 641 | Public: Fired when this thing happens. 642 | 643 | This is a body of the thing 644 | 645 | ### another-event 646 | 647 | Public: Another\ 648 | ` 649 | const doc = parse(str) 650 | expect(doc.events).toEqualJson([{ 651 | name: 'contents-modified', 652 | summary: 'Fired when this thing happens.', 653 | description: 'Fired when this thing happens.\n\nThis is a body of the thing', 654 | visibility: 'Public', 655 | arguments: null 656 | }, { 657 | name: 'another-event', 658 | summary: 'Another', 659 | description: 'Another', 660 | visibility: 'Public', 661 | arguments: null 662 | }]) 663 | }) 664 | ) 665 | 666 | describe('when there should be no output', () => 667 | it('doesnt die when events section is messed up', function () { 668 | const str = 669 | dedent`\ 670 | Public: Batch multiple operations as a single undo/redo step. 671 | 672 | ## Events 673 | 674 | * \`options\` options hash\ 675 | ` 676 | const doc = parse(str) 677 | expect(doc.events).toEqual(null) 678 | }) 679 | ) 680 | }) 681 | 682 | describe('examples section', function () { 683 | it('parses Examples with a description', function () { 684 | const str = 685 | dedent`\ 686 | Public: Batch multiple operations as a single undo/redo step. 687 | 688 | * \`something\` A {Bool} 689 | 690 | ## Examples 691 | 692 | This is example one 693 | 694 | \`\`\`coffee 695 | ok = 1 696 | \`\`\` 697 | 698 | This is example two 699 | 700 | \`\`\`coffee 701 | ok = 2 702 | \`\`\`\ 703 | ` 704 | const doc = parse(str) 705 | expect(doc.examples).toEqualJson([{ 706 | description: 'This is example one', 707 | code: 'ok = 1', 708 | lang: 'coffee', 709 | raw: dedent`\ 710 | \`\`\`coffee 711 | ok = 1 712 | \`\`\`\ 713 | ` 714 | }, { 715 | description: 'This is example two', 716 | code: 'ok = 2', 717 | lang: 'coffee', 718 | raw: dedent`\ 719 | \`\`\`coffee 720 | ok = 2 721 | \`\`\`\ 722 | ` 723 | }]) 724 | }) 725 | 726 | it('parses Examples without a description', function () { 727 | const str = 728 | dedent`\ 729 | Public: Batch multiple operations as a single undo/redo step. 730 | 731 | * \`something\` A {Bool} 732 | 733 | ## Examples 734 | 735 | \`\`\`coffee 736 | ok = 1 737 | \`\`\` 738 | 739 | \`\`\`coffee 740 | ok = 2 741 | \`\`\`\ 742 | ` 743 | const doc = parse(str) 744 | expect(doc.examples).toEqualJson([{ 745 | description: '', 746 | code: 'ok = 1', 747 | lang: 'coffee', 748 | raw: dedent`\ 749 | \`\`\`coffee 750 | ok = 1 751 | \`\`\`\ 752 | ` 753 | }, { 754 | description: '', 755 | code: 'ok = 2', 756 | lang: 'coffee', 757 | raw: dedent`\ 758 | \`\`\`coffee 759 | ok = 2 760 | \`\`\`\ 761 | ` 762 | }]) 763 | }) 764 | 765 | it('ignores examples when no examples specified', function () { 766 | const str = 767 | dedent`\ 768 | Public: Batch multiple operations as a single undo/redo step. 769 | 770 | * \`something\` A {Bool} 771 | 772 | ## Examples\ 773 | ` 774 | const doc = parse(str) 775 | expect(doc.examples).not.toBeDefined() 776 | }) 777 | 778 | describe('when there is an events section above the examples section', () => 779 | it('parses out both the Events and Examples sections', function () { 780 | const str = 781 | dedent`\ 782 | Public: Batch multiple operations as a single undo/redo step. 783 | 784 | ## Events 785 | 786 | Events do this and that and this too. 787 | 788 | ### contents-modified 789 | 790 | Public: Fired when this thing happens. 791 | 792 | ## Examples 793 | 794 | This is example one 795 | 796 | \`\`\`coffee 797 | ok = 1 798 | \`\`\`\ 799 | ` 800 | const doc = parse(str) 801 | expect(doc.events).toEqualJson([{ 802 | name: 'contents-modified', 803 | summary: 'Fired when this thing happens.', 804 | description: 'Fired when this thing happens.', 805 | visibility: 'Public', 806 | arguments: null 807 | } 808 | ]) 809 | expect(doc.examples).toEqualJson([{ 810 | description: 'This is example one', 811 | code: 'ok = 1', 812 | lang: 'coffee', 813 | raw: dedent`\ 814 | \`\`\`coffee 815 | ok = 1 816 | \`\`\`\ 817 | ` 818 | } 819 | ]) 820 | }) 821 | ) 822 | }) 823 | 824 | describe('parsing returns', function () { 825 | describe('when there are arguments', function () { 826 | it('parses returns when the arguments are before the return', function () { 827 | const str = 828 | dedent`\ 829 | Public: Batch multiple operations as a single undo/redo step. 830 | 831 | * \`fn\` A {Function} to call inside the transaction. 832 | 833 | Returns a {Bool}\ 834 | ` 835 | const doc = parse(str) 836 | 837 | expect(doc.arguments).toEqualJson([{ 838 | name: 'fn', 839 | description: 'A {Function} to call inside the transaction.', 840 | type: 'Function', 841 | isOptional: false 842 | } 843 | ]) 844 | 845 | expect(doc.returnValues).toEqualJson([{ 846 | type: 'Bool', 847 | description: 'Returns a {Bool}' 848 | }]) 849 | }) 850 | 851 | it('parses returns when the return is the body and the args are after the return', function () { 852 | const str = 853 | dedent`\ 854 | Public: Returns a {Bool} 855 | 856 | * \`fn\` A {Function} to call inside the transaction.\ 857 | ` 858 | const doc = parse(str) 859 | 860 | expect(doc.arguments).toEqualJson([{ 861 | name: 'fn', 862 | description: 'A {Function} to call inside the transaction.', 863 | type: 'Function', 864 | isOptional: false 865 | } 866 | ]) 867 | 868 | expect(doc.returnValues).toEqualJson([{ 869 | type: 'Bool', 870 | description: 'Returns a {Bool}' 871 | }]) 872 | }) 873 | }) 874 | 875 | it('parses returns when they span multiple lines', function () { 876 | const str = 877 | dedent`\ 878 | Public: Batch multiple operations as a single undo/redo step. 879 | 880 | Returns a {Bool} when 881 | X happens 882 | Returns a {Function} when something else happens\ 883 | ` 884 | const doc = parse(str) 885 | 886 | expect(doc.returnValues).toEqualJson([{ 887 | type: 'Bool', 888 | description: 'Returns a {Bool} when\n X happens' 889 | }, { 890 | type: 'Function', 891 | description: 'Returns a {Function} when something else happens' 892 | }]) 893 | }) 894 | 895 | it('parses returns when there is no description', function () { 896 | const str = 897 | dedent`\ 898 | Public: Returns {Bool} true when Y happens\ 899 | ` 900 | const doc = parse(str) 901 | 902 | expect(doc.summary).toEqual('') 903 | expect(doc.description).toEqual('') 904 | expect(doc.returnValues).toEqualJson([{ 905 | type: 'Bool', 906 | description: 'Returns {Bool} true when Y happens' 907 | }]) 908 | }) 909 | 910 | it('parses returns when they break paragraphs', function () { 911 | const str = 912 | dedent`\ 913 | Public: Batch multiple operations as a single undo/redo step. 914 | 915 | Returns a {Bool} when 916 | X happens 917 | Returns a {Function} when something else happens 918 | 919 | Returns another {Bool} when Y happens\ 920 | ` 921 | const doc = parse(str) 922 | 923 | expect(doc.returnValues).toEqualJson([{ 924 | type: 'Bool', 925 | description: 'Returns a {Bool} when\n X happens' 926 | }, { 927 | type: 'Function', 928 | description: 'Returns a {Function} when something else happens' 929 | }, { 930 | type: 'Bool', 931 | description: 'Returns another {Bool} when Y happens' 932 | }]) 933 | }) 934 | 935 | it('parses return when it contains a list', function () { 936 | const str = 937 | dedent`\ 938 | Public: Batch multiple operations as a single undo/redo step. 939 | 940 | Returns an {Object} with params: 941 | * \`one\` does stuff 942 | * \`two\` does more stuff 943 | Returns null when nothing happens 944 | Returns other when this code is run 945 | 946 | \`\`\`coffee 947 | a = something() 948 | \`\`\`\ 949 | ` 950 | const doc = parse(str) 951 | 952 | expect(doc.returnValues).toEqualJson([{ 953 | type: 'Object', 954 | description: 955 | dedent`\ 956 | Returns an {Object} with params: 957 | 958 | * \`one\` does stuff 959 | * \`two\` does more stuff\ 960 | ` 961 | }, { 962 | type: null, 963 | description: 'Returns null when nothing happens' 964 | }, { 965 | type: null, 966 | description: 967 | dedent`\ 968 | Returns other when this code is run 969 | 970 | \`\`\`coffee 971 | a = something() 972 | \`\`\`\ 973 | ` 974 | }]) 975 | }) 976 | it('parses return when it contains the keyword undefined', function () { 977 | const str = 978 | dedent`\ 979 | Public: Get the active {Package} with the given name. 980 | 981 | Returns undefined.\ 982 | ` 983 | const doc = parse(str) 984 | 985 | expect(doc.returnValues).toEqualJson([{ 986 | type: null, 987 | description: 988 | dedent`\ 989 | Returns undefined.\ 990 | ` 991 | }]) 992 | }) 993 | it('parses return when it contains the keyword `undefined`', function () { 994 | const str = 995 | dedent`\ 996 | Public: Get the active {Package} with the given name. 997 | 998 | Returns \`undefined\`.\ 999 | ` 1000 | const doc = parse(str) 1001 | 1002 | expect(doc.returnValues).toEqualJson([{ 1003 | type: null, 1004 | description: 1005 | dedent`\ 1006 | Returns \`undefined\`.\ 1007 | ` 1008 | }]) 1009 | }) 1010 | 1011 | it('ignores return statements when `parseReturns` is false', function () { 1012 | const str = dedent` 1013 | Public: Get the active {Package} with the given name. 1014 | 1015 | Returns 1. 1016 | Returns 2. 1017 | 1018 | Returns 3. 1019 | 1020 | ## Section 1021 | 1022 | Returns 4. 1023 | ` 1024 | const doc = parse(str, {parseReturns: false}) 1025 | 1026 | expect(doc.visibility).toBe('Public') 1027 | expect(doc.summary).toBe('Get the active {Package} with the given name.') 1028 | expect(doc.description).toBe(dedent` 1029 | Get the active {Package} with the given name. 1030 | 1031 | Returns 1. 1032 | Returns 2. 1033 | 1034 | Returns 3. 1035 | 1036 | ## Section 1037 | 1038 | Returns 4. 1039 | `) 1040 | expect(doc.returnValues).toBeUndefined() 1041 | }) 1042 | }) 1043 | }) 1044 | -------------------------------------------------------------------------------- /src/atomdoc.js: -------------------------------------------------------------------------------- 1 | const {parse} = require('./parser') 2 | module.exports = {parse} 3 | -------------------------------------------------------------------------------- /src/doc.js: -------------------------------------------------------------------------------- 1 | module.exports = 2 | class Doc { 3 | constructor (originalText) { 4 | this.originalText = originalText 5 | this.visibility = 'Private' 6 | } 7 | 8 | isPublic () { 9 | return /public|essential|extended/i.test(this.visibility) 10 | } 11 | 12 | isInternal () { 13 | return /internal/i.test(this.visibility) 14 | } 15 | 16 | isPrivate () { 17 | return !this.isPublic() && !this.isInternal() 18 | } 19 | 20 | setReturnValues (returnValues) { 21 | if (this.returnValues) { 22 | this.returnValues = this.returnValues.concat(returnValues) 23 | } else { 24 | this.returnValues = returnValues 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/parser.js: -------------------------------------------------------------------------------- 1 | const marked = require('marked') 2 | const Doc = require('./doc') 3 | const {getLinkMatch} = require('./utils') 4 | 5 | const SpecialHeadingDepth = 2 6 | const SpecialHeadings = /^Arguments|Events|Examples/ 7 | 8 | const VisibilityRegexStr = '^\\s*([a-zA-Z]+):\\s*' 9 | const VisibilityRegex = new RegExp(VisibilityRegexStr) 10 | const ReturnsRegex = new RegExp(`(${VisibilityRegexStr})?\\s*Returns`) 11 | const ArgumentListItemRegex = /^\s*`([\w\\.-]+)`(\s*[:-])?(\s*\(optional\))?\s*/ 12 | 13 | /* 14 | Section: Parsing 15 | 16 | Translating things from markdown into our json format. 17 | */ 18 | 19 | // Public: Parses a docString 20 | // 21 | // * `docString` a string from the documented object to be parsed 22 | // * `options` an optional {Object} with the following optional keys: 23 | // * `parseReturns`. A {Boolean} describing whether "Returns" statements 24 | // should be parsed or not. Defaults to true. 25 | // 26 | // Returns a {Doc} object 27 | const parse = function (docString, {parseReturns} = {}) { 28 | if (parseReturns == null) { 29 | parseReturns = true 30 | } 31 | 32 | return new Parser(parseReturns).parse(docString) 33 | } 34 | 35 | class Parser { 36 | constructor (parseReturns) { 37 | this.parseReturns = parseReturns 38 | this.stopOnSectionBoundaries = this.stopOnSectionBoundaries.bind(this) 39 | } 40 | 41 | parse (docString) { 42 | const lexer = new marked.Lexer() 43 | const tokens = lexer.lex(docString) 44 | const firstToken = tokens[0] 45 | 46 | if (!firstToken || (firstToken.type !== 'paragraph')) { 47 | throw new Error('Doc string must start with a paragraph!') 48 | } 49 | 50 | const doc = new Doc(docString) 51 | 52 | Object.assign(doc, this.parseSummaryAndDescription(tokens)) 53 | 54 | while (tokens.length) { 55 | let args, events, examples, returnValues, titledArgs 56 | if ((titledArgs = this.parseTitledArgumentsSection(tokens))) { 57 | if (doc.titledArguments == null) doc.titledArguments = [] 58 | doc.titledArguments.push(titledArgs) 59 | } else if ((args = this.parseArgumentsSection(tokens))) { 60 | doc.arguments = args 61 | } else if ((events = this.parseEventsSection(tokens))) { 62 | doc.events = events 63 | } else if ((examples = this.parseExamplesSection(tokens))) { 64 | doc.examples = examples 65 | } else if (this.parseReturns && (returnValues = this.parseReturnValues(tokens, true))) { 66 | doc.setReturnValues(returnValues) 67 | } else { 68 | // These tokens are basically in no-mans land. We'll add them to the 69 | // description so they dont get lost. 70 | const extraDescription = generateDescription(tokens, this.stopOnSectionBoundaries) 71 | doc.description += `\n\n${extraDescription}` 72 | } 73 | } 74 | 75 | return doc 76 | } 77 | 78 | parseSummaryAndDescription (tokens, tokenCallback) { 79 | if (tokenCallback == null) { tokenCallback = this.stopOnSectionBoundaries } 80 | let summary = '' 81 | let description = '' 82 | let visibility = 'Private' 83 | 84 | let rawVisibility = null 85 | let rawSummary = tokens[0].text 86 | if (rawSummary) { 87 | const visibilityMatch = VisibilityRegex.exec(rawSummary) 88 | if (visibilityMatch) { 89 | visibility = visibilityMatch[1] 90 | rawVisibility = visibilityMatch[0] 91 | if (rawVisibility) rawSummary = rawSummary.replace(rawVisibility, '') 92 | } 93 | } 94 | 95 | if (isReturnValue(rawSummary)) { 96 | const returnValues = this.parseReturnValues(tokens, false) 97 | return {summary, description, visibility, returnValues} 98 | } else { 99 | summary = rawSummary 100 | description = generateDescription(tokens, tokenCallback) 101 | if (rawVisibility) description = description.replace(rawVisibility, '') 102 | return {description, summary, visibility} 103 | } 104 | } 105 | 106 | parseArgumentsSection (tokens) { 107 | const firstToken = tokens[0] 108 | if (firstToken && firstToken.type === 'heading') { 109 | if (firstToken.text !== 'Arguments' || firstToken.depth !== SpecialHeadingDepth) return 110 | } else if (firstToken && firstToken.type === 'list_start') { 111 | if (!isAtArgumentList(tokens)) { return } 112 | } else { 113 | return 114 | } 115 | 116 | let args = null 117 | 118 | if (firstToken.type === 'list_start') { 119 | args = this.parseArgumentList(tokens) 120 | } else { 121 | tokens.shift() // consume the header 122 | // consume any BS before the args list 123 | generateDescription(tokens, this.stopOnSectionBoundaries) 124 | args = this.parseArgumentList(tokens) 125 | } 126 | 127 | return args 128 | } 129 | 130 | parseTitledArgumentsSection (tokens) { 131 | const firstToken = tokens[0] 132 | if (!firstToken || firstToken.type !== 'heading') return 133 | if (!firstToken.text.startsWith('Arguments:') || 134 | firstToken.depth !== SpecialHeadingDepth 135 | ) { 136 | return 137 | } 138 | 139 | return { 140 | title: tokens.shift().text.replace('Arguments:', '').trim(), 141 | description: generateDescription(tokens, this.stopOnSectionBoundaries), 142 | arguments: this.parseArgumentList(tokens) 143 | } 144 | } 145 | 146 | parseEventsSection (tokens) { 147 | let firstToken = tokens[0] 148 | if ( 149 | !firstToken || 150 | firstToken.type !== 'heading' || 151 | firstToken.text !== 'Events' || 152 | firstToken.depth !== SpecialHeadingDepth 153 | ) { return } 154 | 155 | const eventHeadingDepth = SpecialHeadingDepth + 1 156 | 157 | // We consume until there is a heading of h3 which denotes the beginning of an event. 158 | const stopTokenCallback = (token, tokens) => { 159 | if ((token.type === 'heading') && (token.depth === eventHeadingDepth)) { 160 | return false 161 | } 162 | return this.stopOnSectionBoundaries(token, tokens) 163 | } 164 | 165 | const events = [] 166 | tokens.shift() // consume the header 167 | 168 | while (tokens.length) { 169 | // We consume until there is a heading of h3 which denotes the beginning of an event. 170 | generateDescription(tokens, stopTokenCallback) 171 | 172 | firstToken = tokens[0] 173 | if ( 174 | firstToken && 175 | firstToken.type === 'heading' && 176 | firstToken.depth === eventHeadingDepth 177 | ) { 178 | tokens.shift() // consume the header 179 | const {summary, description, visibility} = this.parseSummaryAndDescription( 180 | tokens, stopTokenCallback) 181 | const name = firstToken.text 182 | let args = this.parseArgumentList(tokens) 183 | if (args.length === 0) args = null 184 | events.push({name, summary, description, visibility, arguments: args}) 185 | } else { 186 | break 187 | } 188 | } 189 | 190 | if (events.length) { return events } 191 | } 192 | 193 | parseExamplesSection (tokens) { 194 | let firstToken = tokens[0] 195 | if ( 196 | !firstToken || 197 | firstToken.type !== 'heading' || 198 | firstToken.text !== 'Examples' || 199 | firstToken.depth !== SpecialHeadingDepth 200 | ) { return } 201 | 202 | const examples = [] 203 | tokens.shift() // consume the header 204 | 205 | while (tokens.length) { 206 | const description = generateDescription(tokens, (token, tokens) => { 207 | if (token.type === 'code') return false 208 | return this.stopOnSectionBoundaries(token, tokens) 209 | }) 210 | 211 | firstToken = tokens[0] 212 | if (firstToken.type === 'code') { 213 | const example = { 214 | description, 215 | lang: firstToken.lang, 216 | code: firstToken.text, 217 | raw: generateCode(tokens) 218 | } 219 | examples.push(example) 220 | } else { 221 | break 222 | } 223 | } 224 | 225 | if (examples.length) { return examples } 226 | } 227 | 228 | parseReturnValues (tokens, consumeTokensAfterReturn) { 229 | let normalizedString 230 | if (consumeTokensAfterReturn == null) { consumeTokensAfterReturn = false } 231 | const firstToken = tokens[0] 232 | if ( 233 | !firstToken || 234 | !['paragraph', 'text'].includes(firstToken.type) || 235 | !isReturnValue(firstToken.text) 236 | ) { return } 237 | 238 | // there might be a `Public: ` in front of the return. 239 | const returnsMatches = ReturnsRegex.exec(firstToken.text) 240 | if (consumeTokensAfterReturn) { 241 | normalizedString = generateDescription(tokens, () => true) 242 | if (returnsMatches[1]) { 243 | normalizedString = normalizedString.replace(returnsMatches[1], '') 244 | } 245 | } else { 246 | const token = tokens.shift() 247 | normalizedString = token.text 248 | if (returnsMatches[1]) { 249 | normalizedString = normalizedString.replace(returnsMatches[1], '') 250 | } 251 | normalizedString = normalizedString.replace(/\s{2,}/g, ' ') 252 | } 253 | 254 | let returnValues = null 255 | 256 | while (normalizedString) { 257 | const nextIndex = normalizedString.indexOf('Returns', 1) 258 | let returnString = normalizedString 259 | if (nextIndex > -1) { 260 | returnString = normalizedString.substring(0, nextIndex) 261 | normalizedString = normalizedString.substring(nextIndex, normalizedString.length) 262 | } else { 263 | normalizedString = null 264 | } 265 | 266 | if (returnValues == null) { returnValues = [] } 267 | returnValues.push({ 268 | type: getLinkMatch(returnString), 269 | description: returnString.trim() 270 | }) 271 | } 272 | 273 | return returnValues 274 | } 275 | 276 | // Parses argument lists like this one: 277 | // 278 | // * `something` A {Bool} 279 | // * `somethingNested` A nested object 280 | parseArgumentList (tokens) { 281 | let depth = 0 282 | let args = [] 283 | let argumentsList = null 284 | const argumentsListStack = [] 285 | let argument = null 286 | const argumentStack = [] 287 | 288 | while (tokens.length && (tokens[0].type === 'list_start' || depth)) { 289 | const token = tokens[0] 290 | switch (token.type) { 291 | case 'list_start': 292 | // This list might not be a argument list. Check... 293 | const parseAsArgumentList = isAtArgumentList(tokens) 294 | if (parseAsArgumentList) { 295 | depth++ 296 | if (argumentsList) argumentsListStack.push(argumentsList) 297 | argumentsList = [] 298 | tokens.shift() 299 | } else if (argument) { 300 | // If not, consume the list as part of the description 301 | if (!argument.text) argument.text = [] 302 | argument.text.push(`\n${generateList(tokens)}`) 303 | } 304 | break 305 | 306 | case 'list_item_start': 307 | case 'loose_item_start': 308 | if (argument) { argumentStack.push(argument) } 309 | argument = {} 310 | tokens.shift() 311 | break 312 | 313 | case 'code': 314 | if (!argument.text) argument.text = [] 315 | argument.text.push(`\n${generateCode(tokens)}`) 316 | break 317 | 318 | case 'text': 319 | if (!argument.text) argument.text = [] 320 | argument.text.push(token.text) 321 | tokens.shift() 322 | break 323 | 324 | case 'list_item_end': 325 | case 'loose_item_end': 326 | if (argument) { 327 | Object.assign(argument, 328 | this.parseListItem(argument.text.join(' ').replace(/ \n/g, '\n'))) 329 | argumentsList.push(argument) 330 | delete argument.text 331 | } 332 | 333 | argument = argumentStack.pop() 334 | tokens.shift() 335 | break 336 | 337 | case 'list_end': 338 | depth-- 339 | if (argument) { 340 | argument.children = argumentsList 341 | argumentsList = argumentsListStack.pop() 342 | } else { 343 | args = argumentsList 344 | } 345 | tokens.shift() 346 | break 347 | 348 | default: tokens.shift() 349 | } 350 | } 351 | 352 | return args 353 | } 354 | 355 | parseListItem (argumentString) { 356 | let isOptional 357 | let name = null 358 | let type = null 359 | let description = argumentString 360 | 361 | const nameMatches = ArgumentListItemRegex.exec(argumentString) 362 | if (nameMatches) { 363 | name = nameMatches[1] 364 | description = description.replace(nameMatches[0], '') 365 | type = getLinkMatch(description) 366 | isOptional = !!nameMatches[3] 367 | } 368 | 369 | return {name, description, type, isOptional} 370 | } 371 | 372 | stopOnSectionBoundaries (token, tokens) { 373 | if (['paragraph', 'text'].includes(token.type)) { 374 | if (this.parseReturns && isReturnValue(token.text)) { 375 | return false 376 | } 377 | } else if (token.type === 'heading') { 378 | if (token.depth === SpecialHeadingDepth && SpecialHeadings.test(token.text)) { 379 | return false 380 | } 381 | } else if (token.type === 'list_start') { 382 | let listToken = null 383 | for (listToken of tokens) { 384 | if (listToken.type === 'text') break 385 | } 386 | 387 | // Check if list is an arguments list. If it starts with `someVar`, it is. 388 | if (listToken && ArgumentListItemRegex.test(listToken.text)) return false 389 | } 390 | 391 | return true 392 | } 393 | } 394 | 395 | module.exports = {parse} 396 | 397 | /* 398 | Section: Generation 399 | 400 | These methods will consume tokens and return a markdown representation of the 401 | tokens. Yeah, it generates markdown from the lexed markdown tokens. 402 | */ 403 | 404 | const isReturnValue = string => ReturnsRegex.test(string) 405 | 406 | const isArgumentListItem = string => ArgumentListItemRegex.test(string) 407 | 408 | const isAtArgumentList = function (tokens) { 409 | let foundListStart = false 410 | for (let token of tokens) { 411 | if (['list_item_start', 'loose_item_start'].includes(token.type)) { 412 | foundListStart = true 413 | } else if (token.type === 'text' && foundListStart) { 414 | return isArgumentListItem(token.text) 415 | } 416 | } 417 | } 418 | 419 | // Will read / consume tokens down to a special section (args, events, examples) 420 | const generateDescription = function (tokens, tokenCallback) { 421 | let token 422 | const description = [] 423 | while ((token = tokens[0])) { 424 | if ((tokenCallback) && (tokenCallback(token, tokens) === false)) break 425 | 426 | if (['paragraph', 'text'].includes(token.type)) { 427 | description.push(generateParagraph(tokens)) 428 | } else if (token.type === 'blockquote_start') { 429 | description.push(generateBlockquote(tokens)) 430 | } else if (token.type === 'code') { 431 | description.push(generateCode(tokens)) 432 | } else if (token.type === 'heading') { 433 | description.push(generateHeading(tokens)) 434 | } else if (token.type === 'list_start') { 435 | description.push(generateList(tokens)) 436 | } else if (token.type === 'space') { 437 | tokens.shift() 438 | } else { 439 | break 440 | } 441 | } 442 | 443 | return description.join('\n\n') 444 | } 445 | 446 | const generateParagraph = tokens => tokens.shift().text 447 | 448 | const generateHeading = function (tokens) { 449 | const token = tokens.shift() 450 | return `${'#'.repeat(token.depth)} ${token.text}` 451 | } 452 | 453 | const generateBlockquote = function (tokens) { 454 | let token 455 | const lines = [] 456 | 457 | while ((token = tokens.shift())) { 458 | if (token.type === 'blockquote_end') break 459 | if (token.text) { 460 | for (let line of token.text.split('\n')) { 461 | lines.push(`> ${line}`) 462 | } 463 | } 464 | } 465 | 466 | return lines.join('\n') 467 | } 468 | 469 | const generateCode = function (tokens) { 470 | const token = tokens.shift() 471 | const lines = [] 472 | lines.push(token.lang ? `\`\`\`${token.lang}` : '```') 473 | lines.push(token.text) 474 | lines.push('```') 475 | return lines.join('\n') 476 | } 477 | 478 | const generateList = function (tokens) { 479 | let token 480 | let depth = -1 481 | const lines = [] 482 | let linePrefix = null 483 | 484 | let ordered = null 485 | const orderedStack = [] 486 | 487 | const indent = () => ' '.repeat(depth) 488 | 489 | while ((token = tokens[0])) { 490 | let textLines 491 | switch (token.type) { 492 | case 'list_start': 493 | depth++ 494 | orderedStack.push(ordered); 495 | ({ ordered } = token) 496 | break 497 | 498 | case 'list_item_start': 499 | case 'loose_item_start': 500 | linePrefix = ordered ? `${indent()}1. ` : `${indent()}* ` 501 | break 502 | 503 | case 'text': 504 | case 'code': 505 | case 'blockquote_start': 506 | if (token.type === 'code') { 507 | textLines = generateCode(tokens).split('\n') 508 | } else if (token.type === 'blockquote_start') { 509 | textLines = generateBlockquote(tokens).split('\n') 510 | } else { 511 | textLines = token.text.split('\n') 512 | } 513 | 514 | for (let line of textLines) { 515 | const prefix = linePrefix || `${indent()} ` 516 | lines.push(prefix + line) 517 | linePrefix = null 518 | } // we used the bullet! 519 | break 520 | 521 | case 'list_end': 522 | depth-- 523 | ordered = orderedStack.pop() 524 | break 525 | } 526 | 527 | token = tokens.shift() 528 | if (depth < 0) break 529 | } 530 | 531 | return lines.join('\n') 532 | } 533 | -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | getLinkMatch (text) { 3 | const m = text.match(/\{([\w.]+)\}/) 4 | if (m) { 5 | return m[1] 6 | } else { 7 | return null 8 | } 9 | } 10 | } 11 | --------------------------------------------------------------------------------