├── .eslintrc.js ├── .gitignore ├── LICENSE ├── README.md ├── docs ├── index.html ├── litterate.config.js.html ├── main.css └── src │ ├── defaults.js.html │ ├── generate.js.html │ └── index.js.html ├── litterate.config.js ├── package.json ├── src ├── defaults.js ├── generate.js └── index.js ├── templates ├── index.html ├── main.css └── source.html ├── test └── test.js └── yarn.lock /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'env': { 3 | 'browser': true, 4 | 'commonjs': true, 5 | 'es6': true 6 | }, 7 | 'extends': 'eslint:recommended', 8 | 'parserOptions': { 9 | 'ecmaVersion': 2018 10 | }, 11 | 'rules': { 12 | 'accessor-pairs': 'error', 13 | 'array-bracket-newline': [ 14 | 'error', 15 | 'consistent', 16 | ], 17 | 'array-bracket-spacing': [ 18 | 'error', 19 | 'never' 20 | ], 21 | 'array-callback-return': 'error', 22 | 'array-element-newline': 'off', 23 | 'arrow-body-style': 'off', 24 | 'arrow-parens': [ 25 | 'error', 26 | 'as-needed' 27 | ], 28 | 'arrow-spacing': [ 29 | 'error', 30 | { 31 | 'after': true, 32 | 'before': true 33 | } 34 | ], 35 | 'block-scoped-var': 'error', 36 | 'block-spacing': 'error', 37 | 'brace-style': [ 38 | 'error', 39 | '1tbs' 40 | ], 41 | 'callback-return': 'off', 42 | 'camelcase': 'off', 43 | 'capitalized-comments': 'off', 44 | 'class-methods-use-this': 'off', 45 | 'comma-dangle': 'off', 46 | 'comma-spacing': [ 47 | 'error', 48 | { 49 | 'after': true, 50 | 'before': false 51 | } 52 | ], 53 | 'comma-style': [ 54 | 'error', 55 | 'last' 56 | ], 57 | 'comma-dangle': ['error', 'always-multiline'], 58 | 'complexity': 'off', 59 | 'computed-property-spacing': [ 60 | 'error', 61 | 'never' 62 | ], 63 | 'consistent-return': 'error', 64 | 'consistent-this': 'error', 65 | 'curly': [ 66 | 'error', 67 | 'all', 68 | ], 69 | 'default-case': 'off', 70 | 'dot-location': [ 71 | 'error', 72 | 'property' 73 | ], 74 | 'dot-notation': [ 75 | 'error', 76 | { 77 | 'allowKeywords': true 78 | } 79 | ], 80 | 'eol-last': [ 81 | 'error', 82 | 'always', 83 | ], 84 | 'eqeqeq': [ 85 | 'error', 86 | 'always', 87 | ], 88 | 'func-call-spacing': 'error', 89 | 'func-name-matching': 'error', 90 | 'func-names': 'off', 91 | 'func-style': [ 92 | 'error', 93 | 'declaration', 94 | { 95 | 'allowArrowFunctions': true 96 | } 97 | ], 98 | 'function-paren-newline': 'off', 99 | 'generator-star-spacing': 'error', 100 | 'global-require': 'error', 101 | 'guard-for-in': 'off', 102 | 'handle-callback-err': 'error', 103 | 'id-blacklist': 'error', 104 | 'id-length': 'off', 105 | 'id-match': 'error', 106 | 'implicit-arrow-linebreak': [ 107 | 'error', 108 | 'beside' 109 | ], 110 | 'indent': [ 111 | 'error', 112 | 4, 113 | { 114 | 'SwitchCase': 1, 115 | // When expression are indented in multiline templates, 116 | // we don't necessary want them indented to the template start. 117 | 'ignoredNodes': ['TemplateLiteral *'], 118 | } 119 | ], 120 | 'indent-legacy': 'off', 121 | 'init-declarations': 'off', 122 | 'jsx-quotes': 'error', 123 | 'key-spacing': 'error', 124 | 'keyword-spacing': [ 125 | 'error', 126 | { 127 | 'after': true, 128 | 'before': true 129 | } 130 | ], 131 | 'line-comment-position': 'off', 132 | 'linebreak-style': [ 133 | 'error', 134 | 'unix' 135 | ], 136 | 'lines-around-comment': 'error', 137 | 'lines-around-directive': 'error', 138 | 'lines-between-class-members': 'off', 139 | 'max-classes-per-file': 'off', 140 | 'max-depth': 'off', 141 | 'max-len': 'off', 142 | 'max-lines': 'off', 143 | 'max-lines-per-function': 'off', 144 | 'max-nested-callbacks': 'error', 145 | 'max-params': 'off', 146 | 'max-statements': 'off', 147 | 'max-statements-per-line': 'error', 148 | 'multiline-comment-style': 'off', 149 | 'new-parens': 'error', 150 | 'newline-after-var': 'off', 151 | 'newline-before-return': 'off', 152 | 'newline-per-chained-call': 'off', 153 | 'no-alert': 'off', 154 | 'no-array-constructor': 'error', 155 | 'no-async-promise-executor': 'error', 156 | 'no-await-in-loop': 'error', 157 | 'no-bitwise': 'off', 158 | 'no-buffer-constructor': 'error', 159 | 'no-caller': 'error', 160 | 'no-catch-shadow': 'error', 161 | 'no-confusing-arrow': 'off', 162 | 'no-console': 'off', 163 | 'no-continue': 'error', 164 | 'no-div-regex': 'error', 165 | 'no-duplicate-imports': 'error', 166 | 'no-else-return': 'off', 167 | 'no-empty-function': 'off', 168 | 'no-eq-null': 'error', 169 | 'no-eval': 'error', 170 | 'no-extend-native': 'error', 171 | 'no-extra-bind': 'error', 172 | 'no-extra-label': 'error', 173 | 'no-extra-parens': 'off', 174 | 'no-floating-decimal': 'off', 175 | 'no-global-assign': 'error', 176 | 'no-implicit-globals': 'error', 177 | 'no-implied-eval': 'error', 178 | 'no-inline-comments': 'off', 179 | 'no-invalid-this': 'error', 180 | 'no-iterator': 'error', 181 | 'no-label-var': 'error', 182 | 'no-labels': 'error', 183 | 'no-lone-blocks': 'error', 184 | 'no-lonely-if': 'off', 185 | 'no-loop-func': 'error', 186 | 'no-magic-numbers': 'off', 187 | 'no-misleading-character-class': 'error', 188 | 'no-mixed-operators': 'error', 189 | 'no-mixed-requires': 'error', 190 | 'no-multi-assign': 'off', 191 | 'no-multi-spaces': 'off', 192 | 'no-multi-str': 'error', 193 | 'no-multiple-empty-lines': 'error', 194 | 'no-native-reassign': 'error', 195 | 'no-negated-condition': 'off', 196 | 'no-negated-in-lhs': 'error', 197 | 'no-nested-ternary': 'error', 198 | 'no-new': 'error', 199 | 'no-new-func': 'off', 200 | 'no-new-object': 'error', 201 | 'no-new-require': 'error', 202 | 'no-new-wrappers': 'error', 203 | 'no-octal-escape': 'error', 204 | 'no-param-reassign': 'off', 205 | 'no-path-concat': 'error', 206 | 'no-plusplus': 'off', 207 | 'no-process-env': 'off', // for env vars 208 | 'no-process-exit': 'error', 209 | 'no-proto': 'error', 210 | 'no-prototype-builtins': 'error', 211 | 'no-restricted-globals': 'error', 212 | 'no-restricted-imports': 'error', 213 | 'no-restricted-modules': 'error', 214 | 'no-restricted-properties': 'error', 215 | 'no-restricted-syntax': 'error', 216 | 'no-return-assign': 'off', 217 | 'no-return-await': 'error', 218 | 'no-script-url': 'error', 219 | 'no-self-compare': 'error', 220 | 'no-sequences': 'off', 221 | 'no-shadow': 'off', 222 | 'no-shadow-restricted-names': 'error', 223 | 'no-spaced-func': 'error', 224 | 'no-sync': 'off', 225 | 'no-tabs': 'error', 226 | 'no-template-curly-in-string': 'error', 227 | 'no-ternary': 'off', 228 | 'no-throw-literal': 'error', 229 | 'no-trailing-spaces': 'error', 230 | 'no-undef': 'off', 231 | 'no-undef-init': 'error', 232 | 'no-undefined': 'off', 233 | 'no-underscore-dangle': 'off', 234 | 'no-unmodified-loop-condition': 'off', 235 | 'no-unneeded-ternary': 'error', 236 | 'no-unused-vars': [ 237 | 'error', 238 | { 239 | 'args': 'after-used', 240 | 'argsIgnorePattern': '^_', 241 | 'varsIgnorePattern': '^_', 242 | 'ignoreRestSiblings': true, 243 | }, 244 | ], 245 | 'no-unused-expressions': 'error', 246 | 'no-use-before-define': 'off', 247 | 'no-useless-call': 'error', 248 | 'no-useless-catch': 'error', 249 | 'no-useless-computed-key': 'error', 250 | 'no-useless-concat': 'error', 251 | 'no-useless-constructor': 'error', 252 | 'no-useless-rename': 'error', 253 | 'no-useless-return': 'off', 254 | 'no-var': 'error', 255 | 'no-void': 'error', 256 | 'no-warning-comments': 'error', 257 | 'no-whitespace-before-property': 'error', 258 | 'no-with': 'error', 259 | 'nonblock-statement-body-position': 'error', 260 | 'object-curly-newline': 'error', 261 | 'object-curly-spacing': [ 262 | 'error', 263 | 'never' 264 | ], 265 | 'object-shorthand': 'off', 266 | 'one-var': [ 267 | 'error', 268 | 'never', 269 | ], 270 | 'one-var-declaration-per-line': 'error', 271 | 'operator-assignment': [ 272 | 'error', 273 | 'always' 274 | ], 275 | 'operator-linebreak': [ 276 | 'error', 277 | 'before' 278 | ], 279 | 'padded-blocks': 'off', 280 | 'padding-line-between-statements': 'error', 281 | 'prefer-arrow-callback': 'error', 282 | 'prefer-const': [ 283 | 'error', 284 | { 285 | 'destructuring': 'any', 286 | } 287 | ], 288 | 'prefer-destructuring': 'off', 289 | 'prefer-numeric-literals': 'error', 290 | 'prefer-object-spread': 'off', 291 | 'prefer-promise-reject-errors': 'error', 292 | 'prefer-reflect': 'error', 293 | 'prefer-rest-params': 'error', 294 | 'prefer-spread': 'error', 295 | 'prefer-template': 'off', 296 | 'quote-props': 'off', 297 | 'quotes': [ 298 | 'error', 299 | 'single', 300 | { 301 | 'avoidEscape': true, 302 | }, 303 | ], 304 | 'radix': 'error', 305 | 'require-atomic-updates': 'error', 306 | 'require-await': 'error', 307 | 'require-jsdoc': 'off', 308 | 'require-unicode-regexp': 'off', 309 | 'rest-spread-spacing': [ 310 | 'error', 311 | 'never' 312 | ], 313 | // eslint doesn't have an easy option for 'always, 314 | // except after curlybraces' 315 | 'semi': 'off', 316 | 'semi-spacing': [ 317 | 'error', 318 | { 319 | 'after': true, 320 | 'before': false 321 | } 322 | ], 323 | 'semi-style': [ 324 | 'error', 325 | 'last' 326 | ], 327 | 'sort-imports': 'error', 328 | 'sort-keys': 'off', 329 | 'sort-vars': 'off', 330 | 'space-before-blocks': 'error', 331 | 'space-before-function-paren': 'off', 332 | 'space-in-parens': [ 333 | 'error', 334 | 'never' 335 | ], 336 | 'space-infix-ops': 'error', 337 | 'space-unary-ops': [ 338 | 'error', 339 | { 340 | 'words': true, 341 | 'nonwords': false, 342 | 'overrides': { 343 | '++': true, 344 | '--': true, 345 | }, 346 | }, 347 | ], 348 | 'spaced-comment': [ 349 | 'error', 350 | 'always', 351 | { 352 | // for litterate docs 353 | 'markers': ['>'], 354 | } 355 | ], 356 | 'strict': [ 357 | 'error', 358 | 'never' 359 | ], 360 | 'switch-colon-spacing': 'error', 361 | 'symbol-description': 'error', 362 | 'template-curly-spacing': [ 363 | 'error', 364 | 'never' 365 | ], 366 | 'template-tag-spacing': 'error', 367 | 'unicode-bom': [ 368 | 'error', 369 | 'never' 370 | ], 371 | 'valid-jsdoc': 'error', 372 | 'valid-typeof': 'error', 373 | 'vars-on-top': 'error', 374 | 'wrap-iife': 'error', 375 | 'wrap-regex': 'error', 376 | 'yield-star-spacing': 'error', 377 | 'yoda': [ 378 | 'error', 379 | 'never' 380 | ] 381 | } 382 | }; 383 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Litterate 2 | coverage/ 3 | 4 | # Logs 5 | logs 6 | *.log 7 | npm-debug.log* 8 | yarn-debug.log* 9 | yarn-error.log* 10 | 11 | # Runtime data 12 | pids 13 | *.pid 14 | *.seed 15 | *.pid.lock 16 | 17 | # Directory for instrumented libs generated by jscoverage/JSCover 18 | lib-cov 19 | 20 | # Coverage directory used by tools like istanbul 21 | coverage 22 | 23 | # nyc test coverage 24 | .nyc_output 25 | 26 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 27 | .grunt 28 | 29 | # Bower dependency directory (https://bower.io/) 30 | bower_components 31 | 32 | # node-waf configuration 33 | .lock-wscript 34 | 35 | # Compiled binary addons (https://nodejs.org/api/addons.html) 36 | build/Release 37 | 38 | # Dependency directories 39 | node_modules/ 40 | jspm_packages/ 41 | 42 | # TypeScript v1 declaration files 43 | typings/ 44 | 45 | # Optional npm cache directory 46 | .npm 47 | 48 | # Optional eslint cache 49 | .eslintcache 50 | 51 | # Optional REPL history 52 | .node_repl_history 53 | 54 | # Output of 'npm pack' 55 | *.tgz 56 | 57 | # Yarn Integrity file 58 | .yarn-integrity 59 | 60 | # dotenv environment variables file 61 | .env 62 | 63 | # next.js build output 64 | .next 65 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Linus Lee 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # litterate 2 | 3 | [![npm litterate](https://img.shields.io/npm/v/litterate.svg)](http://npm.im/litterate) 4 | [![install size](https://packagephobia.now.sh/badge?p=litterate)](https://packagephobia.now.sh/result?p=litterate) 5 | 6 | Litterate is a command line tool to generate beautiful literate programming-style description of your code from comment annotations. 7 | 8 | Check out Litterate's own source code, annotated with `litterate`, on [GitHub Pages](https://thesephist.github.io/litterate/). 9 | 10 | ## Usage 11 | 12 | If you have [`npx`](https://medium.com/@maybekatz/introducing-npx-an-npm-package-runner-55f7d4bd282b), you can run `litterate` on your project by just running 13 | 14 | ``` 15 | npx litterate 16 | ``` 17 | 18 | which will run Litterate with the default configuration, found in `./src/defaults.js`. 19 | 20 | You can also install `litterate` as a command line tool using `npm install --global litterate`. 21 | 22 | By default, Litterate will count comment blocks starting with `//>` on a newline as annotation blocks (see files under `./src/` for examples). This means Litterate works by default for C-style comment languages (JavaScript, Java, C[++], Rust's normal comments). Litterate can be configured to work with pretty much any language that has beginning-of-line comment delimiters, like `#` in Python or `;` in a variety of other languages. 23 | 24 | You can customize Litterate's output with command line arguments (run `litterate --help` to see options), or with a configuration file, which you can pass to `litterate` with the `--config` command line option. 25 | 26 | ### Usage with npm scripts 27 | 28 | Generally, you'll want to have a configuration you use for your project, and a simple way to run Litterate. For this, one option is to have an npm script that runs Litterate with a configuration file in your project. For example, we may have an npm script: 29 | 30 | ```js 31 | ... 32 | "scripts": { 33 | "docs": "litterate --config litterate.config.js", 34 | }, 35 | ... 36 | ``` 37 | 38 | With this script, running `npm run docs` or `yarn docs` will run Litterate from your NPM dependencies, with the config file you specified. If you use Litterate this way, there's no need to install Litterate globally; just make sure Litterate is installed for your project as a dependency or devDependency. 39 | 40 | ## Configuration options 41 | 42 | Save your configuration in a file, say `litterate.config.js`, and call Litterate with the config with `litterate --config litterate.config.js`. An example configuration file (the one Litterate uses for itself) is in the repo, at `./litterate.config.js`. 43 | 44 | ### `name` 45 | 46 | Name of your project, which shows up as the header and title of the generated documentation site. 47 | 48 | ### `description` 49 | 50 | Description text for your project, shown in the generated site. You can use full Markdown in the description. Litterate uses `marked` to parse Markdown. 51 | 52 | ### `files` 53 | 54 | An array of file paths to annotate. You can specify file paths as full paths or [glob patterns](https://en.wikipedia.org/wiki/Glob_(programming)). On the main page of the generated site, links to individual files will show up in the order they're listed here. 55 | 56 | By default, Litterate annotates all files that match `./src/**/*.js`. 57 | 58 | ### `wrap` 59 | 60 | If 0, long lines of source code will never be wrapped. If any other number, Litterate will wrap long lines to the given number of characters per line. 61 | 62 | ### `baseURL` 63 | 64 | By default, the generated website assumes the root URL of the site is '/', but for GitHub Pages and other sites, you may want to set a different base URL for the site. This allows you to set a different site base URL. 65 | 66 | ### `verbose` 67 | 68 | Verbose output while Litterate runs, useful for debugging. 69 | 70 | ### `output` 71 | 72 | Specify a different destination directory for the generated docs site. By default, Litterate writes to `./docs/`. 73 | 74 | ### `annotationStartMark` and `annotationContinueMark` 75 | 76 | By default, Litterate only counts comment blocks that look like this, as annotation blocks. 77 | 78 | ```javascript 79 | //> Start of annotation block 80 | // continued annotation block 81 | function add(a, b) { 82 | // comment that isn't counted 83 | return a + b; 84 | } 85 | ``` 86 | 87 | This allows you to write `// TODO` comments and other logistical comments without having them be parsed into Litterate annotations. If you'd rather use a different prefix to mark the start and subsequent lines of Litterate anotation blocks, you can override `annotationStartMark` (defaults to `//>`) and `annotationContinueMark` (defaults to `//`). 88 | 89 | If you wanted to count all comments, for example, you could override `annotationStartMark` to `//`. 90 | 91 | ## Contributing 92 | 93 | - `yarn install` to install dependencies (npm should work for these commands too, but the project prefers Yarn and we use a Yarn lockfile.) 94 | 95 | - `yarn docs` to run Litterate on itself, with the configuration file in the repo. Note that this generates pages with the `baseURL` set to `/litterate`, for GitHub pages. Run it with `--baseURL /` to use the default root URL. 96 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Litterate 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |

Litterate

16 |

litterate is a tool to generate beautiful literate programming-style description of your code from comment annotations. Read more at the GitHub repo.

17 | 18 | 19 |
20 | 21 |

Annotated source files

22 | 23 | 24 | 25 | 26 |
27 |

28 |         
29 |
30 | 31 | 32 | -------------------------------------------------------------------------------- /docs/litterate.config.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | ./litterate.config.js annotated source 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |

./litterate.config.js annotated source

16 | Back to index 17 |
18 |

19 |         
20 |

This is the litterate configuration file for litterate itself.

21 |
2module.exports = {
22 |
3    name: 'Litterate',
23 |
4    description: '`litterate` is a tool to generate beautiful literate programming-style description of your code from comment annotations. Read more at [the GitHub repo](https://github.com/thesephist/litterate).',
24 |

We use GitHub Pages to host this generated site, which lives under a /litterate subdirectory

25 |
6    baseURL: '/litterate',
26 |
7    files: [
27 |
8        './src/**/*.js',
28 |
9        './litterate.config.js',
29 |
10    ],
30 |
11}
31 |
12
32 |
33 | 34 | 35 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /docs/main.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | margin: 0; 4 | padding: 0; 5 | font-family: system-ui, 'Helvetica', 'Arial', sans-serif; 6 | } 7 | body { 8 | background: #f8f8f8; 9 | } 10 | main { 11 | display: flex; 12 | flex-direction: column; 13 | justify-content: flex-start; 14 | align-items: flex-start; 15 | margin: 0 auto; 16 | min-height: 100vh; 17 | position: relative; /* to size ::before to full height */ 18 | } 19 | main::before { 20 | content: ''; 21 | display: block; 22 | height: 100%; 23 | width: 440px; 24 | position: absolute; 25 | top: 0; 26 | left: 0; 27 | background: #fff; 28 | z-index: -1; 29 | } 30 | h1, 31 | h2, 32 | h3, 33 | h4, 34 | h5, 35 | h6 { 36 | font-weight: normal; 37 | line-height: 1.3em; 38 | } 39 | .line { 40 | display: flex; 41 | flex-direction: row; 42 | justify-content: flex-start; 43 | align-items: flex-end; 44 | font-size: 16px; 45 | } 46 | .line:first-child .doc { 47 | padding-top: 64px; 48 | } 49 | .line:last-child .doc { 50 | padding-bottom: 64px; 51 | height: 100%; 52 | } 53 | .line:last-child { 54 | align-items: flex-start; 55 | flex-grow: 1; 56 | } 57 | .doc { 58 | min-height: 24px; 59 | box-sizing: border-box; 60 | width: 440px; 61 | line-height: 1.5em; 62 | flex-shrink: 0; 63 | flex-grow: 0; 64 | padding-left: 32px; 65 | padding-right: 32px; 66 | } 67 | .doc p { 68 | margin: 0; 69 | } 70 | pre { 71 | margin: 0; 72 | margin-left: 8px; 73 | line-height: 1.5em; 74 | font-size: 14px; 75 | } 76 | code { 77 | font-size: .9em; 78 | background: #f8f8f8; 79 | box-sizing: border-box; 80 | padding: 2px 4px; 81 | border: 1px solid #aaa; 82 | } 83 | pre, 84 | code { 85 | font-family: 'Menlo', 'Monaco', monospace; 86 | overflow: hidden !important; /* override hljs's scroll style */ 87 | } 88 | .source .lineNumber { 89 | font-weight: normal; 90 | opacity: .2; 91 | margin-right: 18px; 92 | width: 36px; 93 | text-align: right; 94 | display: inline-block; 95 | } 96 | .hljs { 97 | padding: 0 !important; 98 | background: transparent !important; 99 | } 100 | .fade { 101 | opacity: .35; 102 | } 103 | a { 104 | opacity: .8; 105 | color: #777; 106 | display: inline-block; 107 | margin-bottom: 18px; 108 | } 109 | p a { 110 | display: inline; 111 | } 112 | a:hover { 113 | opacity: 1; 114 | } 115 | .doc .sourceLink { 116 | margin-top: 8px; 117 | } 118 | -------------------------------------------------------------------------------- /docs/src/defaults.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | ./src/defaults.js annotated source 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |

./src/defaults.js annotated source

16 | Back to index 17 |
18 |

19 |         
20 |

The default configuration file if the user doesn't specify a value 21 | for any options

22 |
3module.exports = {
23 |
4
24 |
5    name: 'My Project',
25 |
6    description: 'Replace this description by setting the `description` option on `litterate`, or leave it blank',
26 |
7
27 |

Don't wrap lines

28 |
9    wrap: 0,
29 |
10
30 |

By default, it makes sense to assume that the root of the site 31 | is just '/'

32 |
13    baseURL: '/',
33 |
14    verbose: false,
34 |
15
35 |

It's reasonable to assume that most projects keep the main source files in 36 | ./src/, so that's the default files option. We may reverse this call in the future 37 | though to be blank by default.

38 |
19    files: [
39 |
20        './src/**/*.js',
40 |
21    ],
41 |
22
42 |

We default to this because this is where GitHub Pages pulls from.

43 |
24    outputDirectory: './docs/',
44 |
25
45 |
26    annotationStartMark: '//>',
46 |
27    annotationContinueMark: '//',
47 |
28}
48 |
29
49 |
50 | 51 | 52 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /docs/src/generate.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | ./src/generate.js annotated source 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |

./src/generate.js annotated source

16 | Back to index 17 |
18 |

 19 |         
20 |

This file contains the bulk of the logic for generating 21 | litterate pages. This file exports a function that the 22 | command-line utility calls with configurations.

23 |
4
24 |
5const fs = require('fs');
25 |
6const path = require('path');
26 |

Marked is our markdown parser

27 |
8const marked = require('marked');
28 |
9
29 |

This isn't optimal, but for now, we read the three template files into memory at the beginning, 30 | synchronously, so we can reuse them later.

31 |
12const INDEX_PAGE = fs.readFileSync(path.resolve(__dirname, '../templates/index.html'), 'utf8');
32 |
13const STYLES_CSS = fs.readFileSync(path.resolve(__dirname, '../templates/main.css'), 'utf8');
33 |
14const SOURCE_PAGE = fs.readFileSync(path.resolve(__dirname, '../templates/source.html'), 'utf8');
34 |
15
35 |

Helper function to wrap a given line of text into multiple lines, 36 | with limit characters per line.

37 |
18const wrapLine = (line, limit) => {
38 |
19    const len = line.length;
39 |
20    let result = '';
40 |
21    for (let countedChars = 0; countedChars < len; countedChars += limit) {
41 |
22        result += line.substr(countedChars, limit) + '\n';
42 |
23    }
43 |
24    return result;
44 |
25}
45 |
26
46 |

Helper function to scape characters that won't display in HTML correctly, like the very common 47 | > and < and & characters in code.

48 |
29const encodeHTML = code => {
49 |
30    return code.replace(/[\u00A0-\u9999<>&]/gim, i => {
50 |
31        return '&#' + i.codePointAt(0) + ';';
51 |
32    });
52 |
33}
53 |
34
54 |

Litterate uses a very, very minimal templating system that just wraps keywords 55 | in {{curlyBraces}}. We don't need anything complicated, and this allows us to be 56 | lightweight and customizable when needed. This function populates a template with 57 | given key-value pairs.

58 |
39const resolveTemplate = (templateContent, templateValues) => {
59 |
40    for (const [key, value] of Object.entries(templateValues)) {
60 |
41        templateContent = templateContent.replace(
61 |
42            new RegExp(`{{${key}}}`, 'g'),
62 |
43            value,
63 |
44        );
64 |
45    }
65 |
46    return templateContent;
66 |
47}
67 |
48
68 |

Function that maps a given source file to the path where its annotated version 69 | will be saved.

70 |
51const getOutputPathForSourcePath = (sourcePath, config) => {
71 |
52    return path.join(
72 |
53        config.outputDirectory,
73 |
54        sourcePath + '.html',
74 |
55    );
75 |
56}
76 |
57
77 |

Function to populate the index.html page of the generated site with all the source 78 | links, name/description, etc.

79 |
60const populateIndexPage = (sourceFiles, config) => {
80 |
61    const files = sourceFiles.map(sourcePath => {
81 |
62        const outputPath = getOutputPathForSourcePath(sourcePath, config);
82 |
63        return `<p class="sourceLink"><a href="${config.baseURL}${path.relative(config.outputDirectory, outputPath)}">${sourcePath}</a></p>`;
83 |
64    });
84 |
65    return resolveTemplate(INDEX_PAGE, {
85 |
66        title: config.name,
86 |
67        description: marked.parse(config.description),
87 |
68        sourcesList: files.join('\n'),
88 |
69        baseURL: config.baseURL,
89 |
70    });
90 |
71}
91 |
72
92 |

Given an array of source code lines, return an array of lines matched with 93 | any corresponding annotations and the line number from the source file.

94 |
75const linesToLinePairs = (lines, config) => {
95 |
76    const linePairs = [];
96 |
77    let docLine = '';
97 |
78
98 |

Shorthand function to markdown-process and optionally wrap 99 | source code lines.

100 |
81    const processCodeLine = codeLine => {
101 |
82        if (config.wrap !== 0) {
102 |
83            return wrapLine(encodeHTML(codeLine), config.wrap);
103 |
84        } else {
104 |
85            return encodeHTML(codeLine);
105 |
86        }
106 |
87    }
107 |
88
108 |

linesToLinePairs works by having two arrays -- one of the annotation-lineNumber-source line 109 | tuples in order, and another of the annotation lines counted so far for the next source line. 110 | This takes the annotation, line number, and source line from the second array and pushes it 111 | onto the first array, so we can move onto the next lines.

112 |
93    let inAnnotationComment = false;
113 |
94    const pushPair = (codeLine, lineNumber) => {
114 |
95        if (docLine) {
115 |
96            const lastLine = linePairs[linePairs.length - 1];
116 |
97            if (lastLine && lastLine[0]) {
117 |
98                linePairs.push(['', '', '']);
118 |
99            }
119 |
100            linePairs.push([marked.parse(docLine), processCodeLine(codeLine), lineNumber]);
120 |
101        } else {
121 |
102            linePairs.push(['', processCodeLine(codeLine), lineNumber]);
122 |
103        }
123 |
104        docLine = '';
124 |
105    }
125 |
106
126 |

Push the current annotation line onto the array of previous annotation lines, 127 | until we get to the next source code line.

128 |
109    const pushComment = line => {
129 |
110        if (line.trim().startsWith(config.annotationStartMark)) {
130 |
111            docLine = line.replace(config.annotationStartMark, '').trim();
131 |
112        } else {
132 |
113            docLine += '\n' + line.replace(config.annotationContinueMark, '').trim();
133 |
114        }
134 |
115    };
135 |
116
136 |

The main loop for this function.

137 |
118    lines.forEach((line, idx) => {
138 |
119        if (line.trim().startsWith(config.annotationStartMark)) {
139 |
120            inAnnotationComment = true;
140 |
121            pushComment(line);
141 |
122        } else if (line.trim().startsWith(config.annotationContinueMark)) {
142 |
123            if (inAnnotationComment) {
143 |
124                pushComment(line)
144 |
125            } else {
145 |
126                pushPair(line, idx + 1);
146 |
127            }
147 |
128        } else {
148 |
129            if (inAnnotationComment) {
149 |
130                inAnnotationComment = false;
150 |
131            }
151 |
132            pushPair(line, idx + 1);
152 |
133        }
153 |
134    });
154 |
135
155 |
136    return linePairs;
156 |
137}
157 |
138
158 |

This function is called for each source file, to process and save 159 | the Litterate version of the source file in the correct place.

160 |
141const createAndSavePage = (sourcePath, config) => {
161 |
142    const logErr = err => {
162 |
143        if (err) {
163 |
144            console.error(`Error writing ${sourcePath} annotated page: ${err}`);
164 |
145        }
165 |
146    }
166 |
147
167 |
148    return new Promise((res, _rej) => {
168 |
149        fs.readFile(sourcePath, 'utf8', (err, content) => {
169 |
150            if (err) {
170 |
151                logErr();
171 |
152            }
172 |
153
173 |
154            const sourceLines = linesToLinePairs(content.split('\n'), config).map(([doc, source, lineNumber]) => {
174 |
155                return `<div class="line"><div class="doc">${doc}</div><pre class="source javascript"><strong class="lineNumber">${lineNumber}</strong>${source}</pre></div>`;
175 |
156            }).join('\n');
176 |
157
177 |
158            const annotatedPage = resolveTemplate(SOURCE_PAGE, {
178 |
159                title: sourcePath,
179 |
160                lines: sourceLines,
180 |
161                baseURL: config.baseURL,
181 |
162            });
182 |
163            const outputFilePath = getOutputPathForSourcePath(sourcePath, config);
183 |
164            fs.mkdir(path.parse(outputFilePath).dir, {recursive: true}, err => {
184 |
165                if (err) {
185 |
166                    logErr();
186 |
167                }
187 |
168
188 |
169                fs.writeFile(outputFilePath, annotatedPage, 'utf8', err => {
189 |
170                    if (err) {
190 |
171                        logErr();
191 |
172                    }
192 |
173                    res();
193 |
174                });
194 |
175            });
195 |
176        });
196 |
177    });
197 |
178}
198 |
179
199 |

This whole file exports this single function, which is called with a list of files 200 | to process, and the configuration options.

201 |
182const generateLitteratePages = (sourceFiles, config) => {
202 |
183    const {
203 |
184        outputDirectory,
204 |
185    } = config;
205 |
186
206 |

Write out index and main.css files

207 |
188    fs.mkdir(outputDirectory, {recursive: true}, err => {
208 |
189        if (err) {
209 |
190            console.error(`Unable to create ${outputDirectory} for documentation`);
210 |
191        }
211 |
192
212 |
193        fs.writeFile(
213 |
194            path.resolve(outputDirectory, 'index.html'),
214 |
195            populateIndexPage(sourceFiles, config),
215 |
196            'utf8', err => {
216 |
197                if (err) {
217 |
198                    console.error(`Error encountered while writing index.html to disk: ${err}`);
218 |
199                }
219 |
200            },
220 |
201        );
221 |
202
222 |
203        fs.writeFile(path.resolve(outputDirectory, 'main.css'), STYLES_CSS, 'utf8', err => {
223 |
204            if (err) {
224 |
205                console.error(`Error encountered while writing main.css to disk: ${err}`);
225 |
206            }
226 |
207        });
227 |
208    });
228 |
209
229 |

Process source files that need to be annotated

230 |
211    for (const sourceFile of sourceFiles) {
231 |
212        createAndSavePage(sourceFile, config);
232 |
213        console.log(`Annotated ${sourceFile}`);
233 |
214    }
234 |
215}
235 |
216
236 |
217module.exports = {
237 |
218    generateLitteratePages,
238 |
219}
239 |
220
240 |
241 | 242 | 243 | 248 | 249 | 250 | -------------------------------------------------------------------------------- /docs/src/index.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | ./src/index.js annotated source 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |

./src/index.js annotated source

16 | Back to index 17 |
18 |

 19 |         
20 |
1#!/usr/bin/env node
21 |
2
22 |

This file is the entry point for the command-line utility, 23 | and is focused on handling and processing CLI arguments and 24 | figuring out the right options to pass to the docs generator.

25 |
6
26 |
27 |

We use minimist to parse command line arguments (process.argv)

28 |
8const path = require('path');
29 |
9const minimist = require('minimist');
30 |
10const glob = require('glob');
31 |
11const DEFAULTS = require('./defaults.js');
32 |
12const {generateLitteratePages} = require('./generate.js');
33 |
13
34 |

Read + parse command line arguments into a dictionary (object)

35 |
15const ARGS = minimist(process.argv.slice(2));
36 |
16
37 |
17if (ARGS.help || ARGS.h) {
38 |
18    const helpMessage = `
39 |
19    litterate - generate beautiful literate programming-style code annotations
40 |
20    Read the full documentation at https://github.com/thesephist/litterate
41 |
21
42 |
22    Basic usage
43 |
23    ---
44 |
24    litterate --config your-litterate-config.js
45 |
25    litterate [options] [files]
46 |
26        (if no files are specified, litterate runs on src/**/*.js)
47 |
27
48 |
28    Command-line options
49 |
29        (these can be customized in a configuration file as well)
50 |
30    ---
51 |
31    --config    Specify a JS or JSON file for configuration
52 |
32
53 |
33    -n, --name  Name of your project, shown in the generated site.
54 |
34
55 |
35    -d, --description
56 |
36                Description text for your project, shown in the generated site.
57 |
37
58 |
38    -w, --wrap  If 0, long lines of source code will never be wrapped.
59 |
39                If any other number, litterate will wrap long lines to the given
60 |
40                number of characters per line.
61 |
41
62 |
42    -b, --baseURL
63 |
43                By default, the generated website assumes the root URL of the site
64 |
44                is '/', but for GitHub Pages and other sites, you may want to set
65 |
45                a different base URL for the site. This allows you to set a different
66 |
46                site base URL.
67 |
47
68 |
48    -v, --verbose
69 |
49                Verbose output while litterate runs, useful for debugging.
70 |
50
71 |
51    -o, --output
72 |
52                Specify a different destination directory for the generated docs site.
73 |
53                By default, litterate writes to ./docs/.
74 |
54`;
75 |
55    console.log(helpMessage);
76 |

It's OK to process.exit() here because it'll always be 77 | the top-level execution layer of the app, as the entry point to the CLI.

78 |
58    /* eslint-disable-next-line no-process-exit */
79 |
59    process.exit(0);
80 |
60}
81 |
61
82 |
62const userConfigPath = ARGS.config;
83 |
63const USER_CONFIG = userConfigPath ? require(path.resolve(process.cwd(), userConfigPath)) : {};
84 |

This is an easy way to merge two configuration options, with USER_CONFIG overriding anything 85 | specified in defaults.

86 |
66const CONFIG = Object.assign(
87 |
67    {},
88 |
68    DEFAULTS,
89 |
69    USER_CONFIG,
90 |
70);
91 |
71
92 |

Reconcile ARGS, the command-line arguments, and CONFIG together; ARGS overrides 93 | any CONFIG file option.

94 |
74for (const [optionName, optionValue] of Object.entries(ARGS)) {
95 |
75    switch (optionName) {
96 |
76        case 'config':
97 |
77            // do nothing -- ignore
98 |
78            break;
99 |
79        case '_':
100 |
80            if (optionValue.length > 0) {
101 |
81                CONFIG.files = optionValue;
102 |
82            }
103 |
83            break;
104 |
84        case 'n':
105 |
85        case 'name':
106 |
86            CONFIG.name = optionValue;
107 |
87            break;
108 |
88        case 'd':
109 |
89        case 'description':
110 |
90            CONFIG.description = optionValue;
111 |
91            break;
112 |
92        case 'w':
113 |
93        case 'wrap':
114 |
94            CONFIG.wrap = parseInt(optionValue, 10);
115 |
95            break;
116 |
96        case 'b':
117 |
97        case 'baseURL':
118 |
98            CONFIG.baseURL = optionValue;
119 |
99            break;
120 |
100        case 'v':
121 |
101        case 'verbose':
122 |
102            CONFIG.verbose = optionValue;
123 |
103            break;
124 |
104        case 'o':
125 |
105        case 'output':
126 |
106            CONFIG.outputDirectory = optionValue;
127 |
107            break;
128 |
108        default:
129 |
109            throw new Error(`${optionName} is not a valid option, but was set to ${optionValue}`);
130 |
110    }
131 |
111}
132 |
112
133 |

File names are given as glob patterns, which we should expand out.

134 |
114let sourceFiles = [];
135 |
115for (const globPattern of CONFIG.files) {
136 |
116    try {
137 |

Calling the synchronous API here is find, since this is a CLI with one event 138 | in the loop, but it may be faster to switch to the async version later.

139 |
119        const files = glob.sync(globPattern, {
140 |
141 |

This option excludes any directories from the returned match, which we want.

142 |
121            nodir: true,
143 |
144 |

Ignore node modules in matches

145 |
123            ignore: [
146 |
124                '**/node_modules/',
147 |
125            ],
148 |
126        });
149 |
127        sourceFiles = sourceFiles.concat(files);
150 |
128    } catch (err) {
151 |
129        console.log(`Error encountered while looking for matching source files: ${err}`);
152 |
130    }
153 |
131}
154 |
132
155 |

Ensure that the base URL ends with a /

156 |
134CONFIG.baseURL = path.join(CONFIG.baseURL, '/');
157 |
135
158 |
136if (CONFIG.verbose) {
159 |
137    console.log('Using configuration: ', CONFIG);
160 |
138}
161 |
139
162 |
140generateLitteratePages(sourceFiles, CONFIG);
163 |
141
164 |
165 | 166 | 167 | 172 | 173 | 174 | -------------------------------------------------------------------------------- /litterate.config.js: -------------------------------------------------------------------------------- 1 | //> This is the litterate configuration file for litterate itself. 2 | module.exports = { 3 | name: 'Litterate', 4 | description: '`litterate` is a tool to generate beautiful literate programming-style description of your code from comment annotations. Read more at [the GitHub repo](https://github.com/thesephist/litterate).', 5 | //> We use GitHub Pages to host this generated site, which lives under a /litterate subdirectory 6 | baseURL: '/litterate', 7 | files: [ 8 | './src/**/*.js', 9 | './litterate.config.js', 10 | ], 11 | } 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "litterate", 3 | "version": "0.1.5", 4 | "description": "Generate beautiful literate programming-style description of your code from comment annotations", 5 | "main": "src/index.js", 6 | "repository": "git@github.com:thesephist/litterate.git", 7 | "author": "Linus Lee ", 8 | "license": "MIT", 9 | "scripts": { 10 | "docs": "./src/index.js --config ./litterate.config.js", 11 | "test": "mocha test/", 12 | "lint": "eslint ./src/*.js ./litterate.config.js", 13 | "fmt": "eslint --fix ./src/*.js ./litterate.config.js" 14 | }, 15 | "bin": { 16 | "litterate": "./src/index.js" 17 | }, 18 | "dependencies": { 19 | "glob": "^8.0.3", 20 | "marked": "^4.0.18", 21 | "minimist": "^1.2.0" 22 | }, 23 | "devDependencies": { 24 | "chai": "^4.3.6", 25 | "eslint": "^8.20.0", 26 | "mocha": "^10.0.0" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/defaults.js: -------------------------------------------------------------------------------- 1 | //> The default configuration file if the user doesn't specify a value 2 | // for any options 3 | module.exports = { 4 | 5 | name: 'My Project', 6 | description: 'Replace this description by setting the `description` option on `litterate`, or leave it blank', 7 | 8 | //> Don't wrap lines 9 | wrap: 0, 10 | 11 | //> By default, it makes sense to assume that the root of the site 12 | // is just `'/'` 13 | baseURL: '/', 14 | verbose: false, 15 | 16 | //> It's reasonable to assume that most projects keep the main source files in 17 | // `./src/`, so that's the default files option. We may reverse this call in the future 18 | // though to be blank by default. 19 | files: [ 20 | './src/**/*.js', 21 | ], 22 | 23 | //> We default to this because this is where GitHub Pages pulls from. 24 | outputDirectory: './docs/', 25 | 26 | annotationStartMark: '//>', 27 | annotationContinueMark: '//', 28 | } 29 | -------------------------------------------------------------------------------- /src/generate.js: -------------------------------------------------------------------------------- 1 | //> This file contains the bulk of the logic for generating 2 | // litterate pages. This file exports a function that the 3 | // command-line utility calls with configurations. 4 | 5 | const fs = require('fs'); 6 | const path = require('path'); 7 | //> Marked is our markdown parser 8 | const marked = require('marked'); 9 | 10 | //> This isn't optimal, but for now, we read the three template files into memory at the beginning, 11 | // synchronously, so we can reuse them later. 12 | const INDEX_PAGE = fs.readFileSync(path.resolve(__dirname, '../templates/index.html'), 'utf8'); 13 | const STYLES_CSS = fs.readFileSync(path.resolve(__dirname, '../templates/main.css'), 'utf8'); 14 | const SOURCE_PAGE = fs.readFileSync(path.resolve(__dirname, '../templates/source.html'), 'utf8'); 15 | 16 | //> Helper function to wrap a given line of text into multiple lines, 17 | // with `limit` characters per line. 18 | const wrapLine = (line, limit) => { 19 | const len = line.length; 20 | let result = ''; 21 | for (let countedChars = 0; countedChars < len; countedChars += limit) { 22 | result += line.substr(countedChars, limit) + '\n'; 23 | } 24 | return result; 25 | } 26 | 27 | //> Helper function to scape characters that won't display in HTML correctly, like the very common 28 | // `>` and `<` and `&` characters in code. 29 | const encodeHTML = code => { 30 | return code.replace(/[\u00A0-\u9999<>&]/gim, i => { 31 | return '&#' + i.codePointAt(0) + ';'; 32 | }); 33 | } 34 | 35 | //> Litterate uses a very, very minimal templating system that just wraps keywords 36 | // in `{{curlyBraces}}`. We don't need anything complicated, and this allows us to be 37 | // lightweight and customizable when needed. This function populates a template with 38 | // given key-value pairs. 39 | const resolveTemplate = (templateContent, templateValues) => { 40 | for (const [key, value] of Object.entries(templateValues)) { 41 | templateContent = templateContent.replace( 42 | new RegExp(`{{${key}}}`, 'g'), 43 | value, 44 | ); 45 | } 46 | return templateContent; 47 | } 48 | 49 | //> Function that maps a given source file to the path where its annotated version 50 | // will be saved. 51 | const getOutputPathForSourcePath = (sourcePath, config) => { 52 | return path.join( 53 | config.outputDirectory, 54 | sourcePath + '.html', 55 | ); 56 | } 57 | 58 | //> Function to populate the `index.html` page of the generated site with all the source 59 | // links, name/description, etc. 60 | const populateIndexPage = (sourceFiles, config) => { 61 | const files = sourceFiles.map(sourcePath => { 62 | const outputPath = getOutputPathForSourcePath(sourcePath, config); 63 | return ``; 64 | }); 65 | return resolveTemplate(INDEX_PAGE, { 66 | title: config.name, 67 | description: marked.parse(config.description), 68 | sourcesList: files.join('\n'), 69 | baseURL: config.baseURL, 70 | }); 71 | } 72 | 73 | //> Given an array of source code lines, return an array of lines matched with 74 | // any corresponding annotations and the line number from the source file. 75 | const linesToLinePairs = (lines, config) => { 76 | const linePairs = []; 77 | let docLine = ''; 78 | 79 | //> Shorthand function to markdown-process and optionally wrap 80 | // source code lines. 81 | const processCodeLine = codeLine => { 82 | if (config.wrap !== 0) { 83 | return wrapLine(encodeHTML(codeLine), config.wrap); 84 | } else { 85 | return encodeHTML(codeLine); 86 | } 87 | } 88 | 89 | //> `linesToLinePairs` works by having two arrays -- one of the annotation-lineNumber-source line 90 | // tuples in order, and another of the annotation lines counted so far for the next source line. 91 | // This takes the annotation, line number, and source line from the second array and pushes it 92 | // onto the first array, so we can move onto the next lines. 93 | let inAnnotationComment = false; 94 | const pushPair = (codeLine, lineNumber) => { 95 | if (docLine) { 96 | const lastLine = linePairs[linePairs.length - 1]; 97 | if (lastLine && lastLine[0]) { 98 | linePairs.push(['', '', '']); 99 | } 100 | linePairs.push([marked.parse(docLine), processCodeLine(codeLine), lineNumber]); 101 | } else { 102 | linePairs.push(['', processCodeLine(codeLine), lineNumber]); 103 | } 104 | docLine = ''; 105 | } 106 | 107 | //> Push the current annotation line onto the array of previous annotation lines, 108 | // until we get to the next source code line. 109 | const pushComment = line => { 110 | if (line.trim().startsWith(config.annotationStartMark)) { 111 | docLine = line.replace(config.annotationStartMark, '').trim(); 112 | } else { 113 | docLine += '\n' + line.replace(config.annotationContinueMark, '').trim(); 114 | } 115 | }; 116 | 117 | //> The main loop for this function. 118 | lines.forEach((line, idx) => { 119 | if (line.trim().startsWith(config.annotationStartMark)) { 120 | inAnnotationComment = true; 121 | pushComment(line); 122 | } else if (line.trim().startsWith(config.annotationContinueMark)) { 123 | if (inAnnotationComment) { 124 | pushComment(line) 125 | } else { 126 | pushPair(line, idx + 1); 127 | } 128 | } else { 129 | if (inAnnotationComment) { 130 | inAnnotationComment = false; 131 | } 132 | pushPair(line, idx + 1); 133 | } 134 | }); 135 | 136 | return linePairs; 137 | } 138 | 139 | //> This function is called for each source file, to process and save 140 | // the Litterate version of the source file in the correct place. 141 | const createAndSavePage = (sourcePath, config) => { 142 | const logErr = err => { 143 | if (err) { 144 | console.error(`Error writing ${sourcePath} annotated page: ${err}`); 145 | } 146 | } 147 | 148 | return new Promise((res, _rej) => { 149 | fs.readFile(sourcePath, 'utf8', (err, content) => { 150 | if (err) { 151 | logErr(); 152 | } 153 | 154 | const sourceLines = linesToLinePairs(content.split('\n'), config).map(([doc, source, lineNumber]) => { 155 | return `
${doc}
${lineNumber}${source}
`; 156 | }).join('\n'); 157 | 158 | const annotatedPage = resolveTemplate(SOURCE_PAGE, { 159 | title: sourcePath, 160 | lines: sourceLines, 161 | baseURL: config.baseURL, 162 | }); 163 | const outputFilePath = getOutputPathForSourcePath(sourcePath, config); 164 | fs.mkdir(path.parse(outputFilePath).dir, {recursive: true}, err => { 165 | if (err) { 166 | logErr(); 167 | } 168 | 169 | fs.writeFile(outputFilePath, annotatedPage, 'utf8', err => { 170 | if (err) { 171 | logErr(); 172 | } 173 | res(); 174 | }); 175 | }); 176 | }); 177 | }); 178 | } 179 | 180 | //> This whole file exports this single function, which is called with a list of files 181 | // to process, and the configuration options. 182 | const generateLitteratePages = (sourceFiles, config) => { 183 | const { 184 | outputDirectory, 185 | } = config; 186 | 187 | //> Write out index and main.css files 188 | fs.mkdir(outputDirectory, {recursive: true}, err => { 189 | if (err) { 190 | console.error(`Unable to create ${outputDirectory} for documentation`); 191 | } 192 | 193 | fs.writeFile( 194 | path.resolve(outputDirectory, 'index.html'), 195 | populateIndexPage(sourceFiles, config), 196 | 'utf8', err => { 197 | if (err) { 198 | console.error(`Error encountered while writing index.html to disk: ${err}`); 199 | } 200 | }, 201 | ); 202 | 203 | fs.writeFile(path.resolve(outputDirectory, 'main.css'), STYLES_CSS, 'utf8', err => { 204 | if (err) { 205 | console.error(`Error encountered while writing main.css to disk: ${err}`); 206 | } 207 | }); 208 | }); 209 | 210 | //> Process source files that need to be annotated 211 | for (const sourceFile of sourceFiles) { 212 | createAndSavePage(sourceFile, config); 213 | console.log(`Annotated ${sourceFile}`); 214 | } 215 | } 216 | 217 | module.exports = { 218 | generateLitteratePages, 219 | } 220 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | //> This file is the entry point for the command-line utility, 4 | // and is focused on handling and processing CLI arguments and 5 | // figuring out the right options to pass to the docs generator. 6 | 7 | //> We use `minimist` to parse command line arguments (`process.argv`) 8 | const path = require('path'); 9 | const minimist = require('minimist'); 10 | const glob = require('glob'); 11 | const DEFAULTS = require('./defaults.js'); 12 | const {generateLitteratePages} = require('./generate.js'); 13 | 14 | //> Read + parse command line arguments into a dictionary (object) 15 | const ARGS = minimist(process.argv.slice(2)); 16 | 17 | if (ARGS.help || ARGS.h) { 18 | const helpMessage = ` 19 | litterate - generate beautiful literate programming-style code annotations 20 | Read the full documentation at https://github.com/thesephist/litterate 21 | 22 | Basic usage 23 | --- 24 | litterate --config your-litterate-config.js 25 | litterate [options] [files] 26 | (if no files are specified, litterate runs on src/**/*.js) 27 | 28 | Command-line options 29 | (these can be customized in a configuration file as well) 30 | --- 31 | --config Specify a JS or JSON file for configuration 32 | 33 | -n, --name Name of your project, shown in the generated site. 34 | 35 | -d, --description 36 | Description text for your project, shown in the generated site. 37 | 38 | -w, --wrap If 0, long lines of source code will never be wrapped. 39 | If any other number, litterate will wrap long lines to the given 40 | number of characters per line. 41 | 42 | -b, --baseURL 43 | By default, the generated website assumes the root URL of the site 44 | is '/', but for GitHub Pages and other sites, you may want to set 45 | a different base URL for the site. This allows you to set a different 46 | site base URL. 47 | 48 | -v, --verbose 49 | Verbose output while litterate runs, useful for debugging. 50 | 51 | -o, --output 52 | Specify a different destination directory for the generated docs site. 53 | By default, litterate writes to ./docs/. 54 | `; 55 | console.log(helpMessage); 56 | //> It's OK to `process.exit()` here because it'll always be 57 | // the top-level execution layer of the app, as the entry point to the CLI. 58 | /* eslint-disable-next-line no-process-exit */ 59 | process.exit(0); 60 | } 61 | 62 | const userConfigPath = ARGS.config; 63 | const USER_CONFIG = userConfigPath ? require(path.resolve(process.cwd(), userConfigPath)) : {}; 64 | //> This is an easy way to merge two configuration options, with `USER_CONFIG` overriding anything 65 | // specified in defaults. 66 | const CONFIG = Object.assign( 67 | {}, 68 | DEFAULTS, 69 | USER_CONFIG, 70 | ); 71 | 72 | //> Reconcile `ARGS`, the command-line arguments, and `CONFIG` together; `ARGS` overrides 73 | // any `CONFIG` file option. 74 | for (const [optionName, optionValue] of Object.entries(ARGS)) { 75 | switch (optionName) { 76 | case 'config': 77 | // do nothing -- ignore 78 | break; 79 | case '_': 80 | if (optionValue.length > 0) { 81 | CONFIG.files = optionValue; 82 | } 83 | break; 84 | case 'n': 85 | case 'name': 86 | CONFIG.name = optionValue; 87 | break; 88 | case 'd': 89 | case 'description': 90 | CONFIG.description = optionValue; 91 | break; 92 | case 'w': 93 | case 'wrap': 94 | CONFIG.wrap = parseInt(optionValue, 10); 95 | break; 96 | case 'b': 97 | case 'baseURL': 98 | CONFIG.baseURL = optionValue; 99 | break; 100 | case 'v': 101 | case 'verbose': 102 | CONFIG.verbose = optionValue; 103 | break; 104 | case 'o': 105 | case 'output': 106 | CONFIG.outputDirectory = optionValue; 107 | break; 108 | default: 109 | throw new Error(`${optionName} is not a valid option, but was set to ${optionValue}`); 110 | } 111 | } 112 | 113 | //> File names are given as glob patterns, which we should expand out. 114 | let sourceFiles = []; 115 | for (const globPattern of CONFIG.files) { 116 | try { 117 | //> Calling the synchronous API here is find, since this is a CLI with one event 118 | // in the loop, but it may be faster to switch to the async version later. 119 | const files = glob.sync(globPattern, { 120 | //> This option excludes any directories from the returned match, which we want. 121 | nodir: true, 122 | //> Ignore node modules in matches 123 | ignore: [ 124 | '**/node_modules/', 125 | ], 126 | }); 127 | sourceFiles = sourceFiles.concat(files); 128 | } catch (err) { 129 | console.log(`Error encountered while looking for matching source files: ${err}`); 130 | } 131 | } 132 | 133 | //> Ensure that the base URL ends with a `/` 134 | CONFIG.baseURL = path.join(CONFIG.baseURL, '/'); 135 | 136 | if (CONFIG.verbose) { 137 | console.log('Using configuration: ', CONFIG); 138 | } 139 | 140 | generateLitteratePages(sourceFiles, CONFIG); 141 | -------------------------------------------------------------------------------- /templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | {{title}} 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |

{{title}}

16 | {{description}} 17 | 18 |
19 | 20 |

Annotated source files

21 | {{sourcesList}} 22 |
23 |

24 |         
25 |
26 | 27 | 28 | -------------------------------------------------------------------------------- /templates/main.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | margin: 0; 4 | padding: 0; 5 | font-family: system-ui, 'Helvetica', 'Arial', sans-serif; 6 | } 7 | body { 8 | background: #f8f8f8; 9 | } 10 | main { 11 | display: flex; 12 | flex-direction: column; 13 | justify-content: flex-start; 14 | align-items: flex-start; 15 | margin: 0 auto; 16 | min-height: 100vh; 17 | position: relative; /* to size ::before to full height */ 18 | } 19 | main::before { 20 | content: ''; 21 | display: block; 22 | height: 100%; 23 | width: 440px; 24 | position: absolute; 25 | top: 0; 26 | left: 0; 27 | background: #fff; 28 | z-index: -1; 29 | } 30 | h1, 31 | h2, 32 | h3, 33 | h4, 34 | h5, 35 | h6 { 36 | font-weight: normal; 37 | line-height: 1.3em; 38 | } 39 | .line { 40 | display: flex; 41 | flex-direction: row; 42 | justify-content: flex-start; 43 | align-items: flex-end; 44 | font-size: 16px; 45 | } 46 | .line:first-child .doc { 47 | padding-top: 64px; 48 | } 49 | .line:last-child .doc { 50 | padding-bottom: 64px; 51 | height: 100%; 52 | } 53 | .line:last-child { 54 | align-items: flex-start; 55 | flex-grow: 1; 56 | } 57 | .doc { 58 | min-height: 24px; 59 | box-sizing: border-box; 60 | width: 440px; 61 | line-height: 1.5em; 62 | flex-shrink: 0; 63 | flex-grow: 0; 64 | padding-left: 32px; 65 | padding-right: 32px; 66 | } 67 | .doc p { 68 | margin: 0; 69 | } 70 | pre { 71 | margin: 0; 72 | margin-left: 8px; 73 | line-height: 1.5em; 74 | font-size: 14px; 75 | } 76 | code { 77 | font-size: .9em; 78 | background: #f8f8f8; 79 | box-sizing: border-box; 80 | padding: 2px 4px; 81 | border: 1px solid #aaa; 82 | } 83 | pre, 84 | code { 85 | font-family: 'Menlo', 'Monaco', monospace; 86 | overflow: hidden !important; /* override hljs's scroll style */ 87 | } 88 | .source .lineNumber { 89 | font-weight: normal; 90 | opacity: .2; 91 | margin-right: 18px; 92 | width: 36px; 93 | text-align: right; 94 | display: inline-block; 95 | } 96 | .hljs { 97 | padding: 0 !important; 98 | background: transparent !important; 99 | } 100 | .fade { 101 | opacity: .35; 102 | } 103 | a { 104 | opacity: .8; 105 | color: #777; 106 | display: inline-block; 107 | margin-bottom: 18px; 108 | } 109 | p a { 110 | display: inline; 111 | } 112 | a:hover { 113 | opacity: 1; 114 | } 115 | .doc .sourceLink { 116 | margin-top: 8px; 117 | } 118 | -------------------------------------------------------------------------------- /templates/source.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | {{title}} annotated source 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |

{{title}} annotated source

16 | Back to index 17 |
18 |

19 |         
20 | {{lines}} 21 |
22 | 23 | 24 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thesephist/litterate/2fbdabf526bbf9e28ad38da64812bb56521c892b/test/test.js -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@eslint/eslintrc@^1.3.0": 6 | version "1.3.0" 7 | resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.0.tgz#29f92c30bb3e771e4a2048c95fa6855392dfac4f" 8 | integrity sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw== 9 | dependencies: 10 | ajv "^6.12.4" 11 | debug "^4.3.2" 12 | espree "^9.3.2" 13 | globals "^13.15.0" 14 | ignore "^5.2.0" 15 | import-fresh "^3.2.1" 16 | js-yaml "^4.1.0" 17 | minimatch "^3.1.2" 18 | strip-json-comments "^3.1.1" 19 | 20 | "@humanwhocodes/config-array@^0.9.2": 21 | version "0.9.5" 22 | resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.5.tgz#2cbaf9a89460da24b5ca6531b8bbfc23e1df50c7" 23 | integrity sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw== 24 | dependencies: 25 | "@humanwhocodes/object-schema" "^1.2.1" 26 | debug "^4.1.1" 27 | minimatch "^3.0.4" 28 | 29 | "@humanwhocodes/object-schema@^1.2.1": 30 | version "1.2.1" 31 | resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" 32 | integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== 33 | 34 | "@ungap/promise-all-settled@1.1.2": 35 | version "1.1.2" 36 | resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" 37 | integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== 38 | 39 | acorn-jsx@^5.3.2: 40 | version "5.3.2" 41 | resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" 42 | integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== 43 | 44 | acorn@^8.7.1: 45 | version "8.7.1" 46 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30" 47 | integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A== 48 | 49 | ajv@^6.10.0, ajv@^6.12.4: 50 | version "6.12.6" 51 | resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" 52 | integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== 53 | dependencies: 54 | fast-deep-equal "^3.1.1" 55 | fast-json-stable-stringify "^2.0.0" 56 | json-schema-traverse "^0.4.1" 57 | uri-js "^4.2.2" 58 | 59 | ansi-colors@4.1.1: 60 | version "4.1.1" 61 | resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" 62 | integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== 63 | 64 | ansi-regex@^5.0.1: 65 | version "5.0.1" 66 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" 67 | integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== 68 | 69 | ansi-styles@^4.0.0, ansi-styles@^4.1.0: 70 | version "4.3.0" 71 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" 72 | integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== 73 | dependencies: 74 | color-convert "^2.0.1" 75 | 76 | anymatch@~3.1.2: 77 | version "3.1.2" 78 | resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" 79 | integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== 80 | dependencies: 81 | normalize-path "^3.0.0" 82 | picomatch "^2.0.4" 83 | 84 | argparse@^2.0.1: 85 | version "2.0.1" 86 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" 87 | integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== 88 | 89 | assertion-error@^1.1.0: 90 | version "1.1.0" 91 | resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" 92 | integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== 93 | 94 | balanced-match@^1.0.0: 95 | version "1.0.2" 96 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" 97 | integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== 98 | 99 | binary-extensions@^2.0.0: 100 | version "2.2.0" 101 | resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" 102 | integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== 103 | 104 | brace-expansion@^1.1.7: 105 | version "1.1.11" 106 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 107 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 108 | dependencies: 109 | balanced-match "^1.0.0" 110 | concat-map "0.0.1" 111 | 112 | brace-expansion@^2.0.1: 113 | version "2.0.1" 114 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" 115 | integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== 116 | dependencies: 117 | balanced-match "^1.0.0" 118 | 119 | braces@~3.0.2: 120 | version "3.0.2" 121 | resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" 122 | integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== 123 | dependencies: 124 | fill-range "^7.0.1" 125 | 126 | browser-stdout@1.3.1: 127 | version "1.3.1" 128 | resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" 129 | integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== 130 | 131 | callsites@^3.0.0: 132 | version "3.1.0" 133 | resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" 134 | integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== 135 | 136 | camelcase@^6.0.0: 137 | version "6.3.0" 138 | resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" 139 | integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== 140 | 141 | chai@^4.3.6: 142 | version "4.3.6" 143 | resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.6.tgz#ffe4ba2d9fa9d6680cc0b370adae709ec9011e9c" 144 | integrity sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q== 145 | dependencies: 146 | assertion-error "^1.1.0" 147 | check-error "^1.0.2" 148 | deep-eql "^3.0.1" 149 | get-func-name "^2.0.0" 150 | loupe "^2.3.1" 151 | pathval "^1.1.1" 152 | type-detect "^4.0.5" 153 | 154 | chalk@^4.0.0, chalk@^4.1.0: 155 | version "4.1.2" 156 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" 157 | integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== 158 | dependencies: 159 | ansi-styles "^4.1.0" 160 | supports-color "^7.1.0" 161 | 162 | check-error@^1.0.2: 163 | version "1.0.2" 164 | resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" 165 | integrity sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA== 166 | 167 | chokidar@3.5.3: 168 | version "3.5.3" 169 | resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" 170 | integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== 171 | dependencies: 172 | anymatch "~3.1.2" 173 | braces "~3.0.2" 174 | glob-parent "~5.1.2" 175 | is-binary-path "~2.1.0" 176 | is-glob "~4.0.1" 177 | normalize-path "~3.0.0" 178 | readdirp "~3.6.0" 179 | optionalDependencies: 180 | fsevents "~2.3.2" 181 | 182 | cliui@^7.0.2: 183 | version "7.0.4" 184 | resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" 185 | integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== 186 | dependencies: 187 | string-width "^4.2.0" 188 | strip-ansi "^6.0.0" 189 | wrap-ansi "^7.0.0" 190 | 191 | color-convert@^2.0.1: 192 | version "2.0.1" 193 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" 194 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== 195 | dependencies: 196 | color-name "~1.1.4" 197 | 198 | color-name@~1.1.4: 199 | version "1.1.4" 200 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" 201 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== 202 | 203 | concat-map@0.0.1: 204 | version "0.0.1" 205 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 206 | integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== 207 | 208 | cross-spawn@^7.0.2: 209 | version "7.0.3" 210 | resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" 211 | integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== 212 | dependencies: 213 | path-key "^3.1.0" 214 | shebang-command "^2.0.0" 215 | which "^2.0.1" 216 | 217 | debug@4.3.4, debug@^4.1.1, debug@^4.3.2: 218 | version "4.3.4" 219 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" 220 | integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== 221 | dependencies: 222 | ms "2.1.2" 223 | 224 | decamelize@^4.0.0: 225 | version "4.0.0" 226 | resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" 227 | integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== 228 | 229 | deep-eql@^3.0.1: 230 | version "3.0.1" 231 | resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" 232 | integrity sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw== 233 | dependencies: 234 | type-detect "^4.0.0" 235 | 236 | deep-is@^0.1.3: 237 | version "0.1.4" 238 | resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" 239 | integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== 240 | 241 | diff@5.0.0: 242 | version "5.0.0" 243 | resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" 244 | integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== 245 | 246 | doctrine@^3.0.0: 247 | version "3.0.0" 248 | resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" 249 | integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== 250 | dependencies: 251 | esutils "^2.0.2" 252 | 253 | emoji-regex@^8.0.0: 254 | version "8.0.0" 255 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" 256 | integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== 257 | 258 | escalade@^3.1.1: 259 | version "3.1.1" 260 | resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" 261 | integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== 262 | 263 | escape-string-regexp@4.0.0, escape-string-regexp@^4.0.0: 264 | version "4.0.0" 265 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" 266 | integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== 267 | 268 | eslint-scope@^7.1.1: 269 | version "7.1.1" 270 | resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" 271 | integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== 272 | dependencies: 273 | esrecurse "^4.3.0" 274 | estraverse "^5.2.0" 275 | 276 | eslint-utils@^3.0.0: 277 | version "3.0.0" 278 | resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" 279 | integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== 280 | dependencies: 281 | eslint-visitor-keys "^2.0.0" 282 | 283 | eslint-visitor-keys@^2.0.0: 284 | version "2.1.0" 285 | resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" 286 | integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== 287 | 288 | eslint-visitor-keys@^3.3.0: 289 | version "3.3.0" 290 | resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" 291 | integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== 292 | 293 | eslint@^8.20.0: 294 | version "8.20.0" 295 | resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.20.0.tgz#048ac56aa18529967da8354a478be4ec0a2bc81b" 296 | integrity sha512-d4ixhz5SKCa1D6SCPrivP7yYVi7nyD6A4vs6HIAul9ujBzcEmZVM3/0NN/yu5nKhmO1wjp5xQ46iRfmDGlOviA== 297 | dependencies: 298 | "@eslint/eslintrc" "^1.3.0" 299 | "@humanwhocodes/config-array" "^0.9.2" 300 | ajv "^6.10.0" 301 | chalk "^4.0.0" 302 | cross-spawn "^7.0.2" 303 | debug "^4.3.2" 304 | doctrine "^3.0.0" 305 | escape-string-regexp "^4.0.0" 306 | eslint-scope "^7.1.1" 307 | eslint-utils "^3.0.0" 308 | eslint-visitor-keys "^3.3.0" 309 | espree "^9.3.2" 310 | esquery "^1.4.0" 311 | esutils "^2.0.2" 312 | fast-deep-equal "^3.1.3" 313 | file-entry-cache "^6.0.1" 314 | functional-red-black-tree "^1.0.1" 315 | glob-parent "^6.0.1" 316 | globals "^13.15.0" 317 | ignore "^5.2.0" 318 | import-fresh "^3.0.0" 319 | imurmurhash "^0.1.4" 320 | is-glob "^4.0.0" 321 | js-yaml "^4.1.0" 322 | json-stable-stringify-without-jsonify "^1.0.1" 323 | levn "^0.4.1" 324 | lodash.merge "^4.6.2" 325 | minimatch "^3.1.2" 326 | natural-compare "^1.4.0" 327 | optionator "^0.9.1" 328 | regexpp "^3.2.0" 329 | strip-ansi "^6.0.1" 330 | strip-json-comments "^3.1.0" 331 | text-table "^0.2.0" 332 | v8-compile-cache "^2.0.3" 333 | 334 | espree@^9.3.2: 335 | version "9.3.2" 336 | resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.2.tgz#f58f77bd334731182801ced3380a8cc859091596" 337 | integrity sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA== 338 | dependencies: 339 | acorn "^8.7.1" 340 | acorn-jsx "^5.3.2" 341 | eslint-visitor-keys "^3.3.0" 342 | 343 | esquery@^1.4.0: 344 | version "1.4.0" 345 | resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" 346 | integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== 347 | dependencies: 348 | estraverse "^5.1.0" 349 | 350 | esrecurse@^4.3.0: 351 | version "4.3.0" 352 | resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" 353 | integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== 354 | dependencies: 355 | estraverse "^5.2.0" 356 | 357 | estraverse@^5.1.0, estraverse@^5.2.0: 358 | version "5.3.0" 359 | resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" 360 | integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== 361 | 362 | esutils@^2.0.2: 363 | version "2.0.3" 364 | resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" 365 | integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== 366 | 367 | fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: 368 | version "3.1.3" 369 | resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" 370 | integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== 371 | 372 | fast-json-stable-stringify@^2.0.0: 373 | version "2.1.0" 374 | resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" 375 | integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== 376 | 377 | fast-levenshtein@^2.0.6: 378 | version "2.0.6" 379 | resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" 380 | integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== 381 | 382 | file-entry-cache@^6.0.1: 383 | version "6.0.1" 384 | resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" 385 | integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== 386 | dependencies: 387 | flat-cache "^3.0.4" 388 | 389 | fill-range@^7.0.1: 390 | version "7.0.1" 391 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" 392 | integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== 393 | dependencies: 394 | to-regex-range "^5.0.1" 395 | 396 | find-up@5.0.0: 397 | version "5.0.0" 398 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" 399 | integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== 400 | dependencies: 401 | locate-path "^6.0.0" 402 | path-exists "^4.0.0" 403 | 404 | flat-cache@^3.0.4: 405 | version "3.0.4" 406 | resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" 407 | integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== 408 | dependencies: 409 | flatted "^3.1.0" 410 | rimraf "^3.0.2" 411 | 412 | flat@^5.0.2: 413 | version "5.0.2" 414 | resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" 415 | integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== 416 | 417 | flatted@^3.1.0: 418 | version "3.2.6" 419 | resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.6.tgz#022e9218c637f9f3fc9c35ab9c9193f05add60b2" 420 | integrity sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ== 421 | 422 | fs.realpath@^1.0.0: 423 | version "1.0.0" 424 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 425 | integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== 426 | 427 | fsevents@~2.3.2: 428 | version "2.3.2" 429 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" 430 | integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== 431 | 432 | functional-red-black-tree@^1.0.1: 433 | version "1.0.1" 434 | resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" 435 | integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g== 436 | 437 | get-caller-file@^2.0.5: 438 | version "2.0.5" 439 | resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" 440 | integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== 441 | 442 | get-func-name@^2.0.0: 443 | version "2.0.0" 444 | resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" 445 | integrity sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig== 446 | 447 | glob-parent@^6.0.1: 448 | version "6.0.2" 449 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" 450 | integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== 451 | dependencies: 452 | is-glob "^4.0.3" 453 | 454 | glob-parent@~5.1.2: 455 | version "5.1.2" 456 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" 457 | integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== 458 | dependencies: 459 | is-glob "^4.0.1" 460 | 461 | glob@7.2.0: 462 | version "7.2.0" 463 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" 464 | integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== 465 | dependencies: 466 | fs.realpath "^1.0.0" 467 | inflight "^1.0.4" 468 | inherits "2" 469 | minimatch "^3.0.4" 470 | once "^1.3.0" 471 | path-is-absolute "^1.0.0" 472 | 473 | glob@^7.1.3: 474 | version "7.2.3" 475 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" 476 | integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== 477 | dependencies: 478 | fs.realpath "^1.0.0" 479 | inflight "^1.0.4" 480 | inherits "2" 481 | minimatch "^3.1.1" 482 | once "^1.3.0" 483 | path-is-absolute "^1.0.0" 484 | 485 | glob@^8.0.3: 486 | version "8.0.3" 487 | resolved "https://registry.yarnpkg.com/glob/-/glob-8.0.3.tgz#415c6eb2deed9e502c68fa44a272e6da6eeca42e" 488 | integrity sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ== 489 | dependencies: 490 | fs.realpath "^1.0.0" 491 | inflight "^1.0.4" 492 | inherits "2" 493 | minimatch "^5.0.1" 494 | once "^1.3.0" 495 | 496 | globals@^13.15.0: 497 | version "13.16.0" 498 | resolved "https://registry.yarnpkg.com/globals/-/globals-13.16.0.tgz#9be4aca28f311aaeb974ea54978ebbb5e35ce46a" 499 | integrity sha512-A1lrQfpNF+McdPOnnFqY3kSN0AFTy485bTi1bkLk4mVPODIUEcSfhHgRqA+QdXPksrSTTztYXx37NFV+GpGk3Q== 500 | dependencies: 501 | type-fest "^0.20.2" 502 | 503 | has-flag@^4.0.0: 504 | version "4.0.0" 505 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" 506 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== 507 | 508 | he@1.2.0: 509 | version "1.2.0" 510 | resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" 511 | integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== 512 | 513 | ignore@^5.2.0: 514 | version "5.2.0" 515 | resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" 516 | integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== 517 | 518 | import-fresh@^3.0.0, import-fresh@^3.2.1: 519 | version "3.3.0" 520 | resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" 521 | integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== 522 | dependencies: 523 | parent-module "^1.0.0" 524 | resolve-from "^4.0.0" 525 | 526 | imurmurhash@^0.1.4: 527 | version "0.1.4" 528 | resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" 529 | integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== 530 | 531 | inflight@^1.0.4: 532 | version "1.0.6" 533 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 534 | integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== 535 | dependencies: 536 | once "^1.3.0" 537 | wrappy "1" 538 | 539 | inherits@2: 540 | version "2.0.4" 541 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 542 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 543 | 544 | is-binary-path@~2.1.0: 545 | version "2.1.0" 546 | resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" 547 | integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== 548 | dependencies: 549 | binary-extensions "^2.0.0" 550 | 551 | is-extglob@^2.1.1: 552 | version "2.1.1" 553 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" 554 | integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== 555 | 556 | is-fullwidth-code-point@^3.0.0: 557 | version "3.0.0" 558 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" 559 | integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== 560 | 561 | is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: 562 | version "4.0.3" 563 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" 564 | integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== 565 | dependencies: 566 | is-extglob "^2.1.1" 567 | 568 | is-number@^7.0.0: 569 | version "7.0.0" 570 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" 571 | integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== 572 | 573 | is-plain-obj@^2.1.0: 574 | version "2.1.0" 575 | resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" 576 | integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== 577 | 578 | is-unicode-supported@^0.1.0: 579 | version "0.1.0" 580 | resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" 581 | integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== 582 | 583 | isexe@^2.0.0: 584 | version "2.0.0" 585 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" 586 | integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== 587 | 588 | js-yaml@4.1.0, js-yaml@^4.1.0: 589 | version "4.1.0" 590 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" 591 | integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== 592 | dependencies: 593 | argparse "^2.0.1" 594 | 595 | json-schema-traverse@^0.4.1: 596 | version "0.4.1" 597 | resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" 598 | integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== 599 | 600 | json-stable-stringify-without-jsonify@^1.0.1: 601 | version "1.0.1" 602 | resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" 603 | integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== 604 | 605 | levn@^0.4.1: 606 | version "0.4.1" 607 | resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" 608 | integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== 609 | dependencies: 610 | prelude-ls "^1.2.1" 611 | type-check "~0.4.0" 612 | 613 | locate-path@^6.0.0: 614 | version "6.0.0" 615 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" 616 | integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== 617 | dependencies: 618 | p-locate "^5.0.0" 619 | 620 | lodash.merge@^4.6.2: 621 | version "4.6.2" 622 | resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" 623 | integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== 624 | 625 | log-symbols@4.1.0: 626 | version "4.1.0" 627 | resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" 628 | integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== 629 | dependencies: 630 | chalk "^4.1.0" 631 | is-unicode-supported "^0.1.0" 632 | 633 | loupe@^2.3.1: 634 | version "2.3.4" 635 | resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.4.tgz#7e0b9bffc76f148f9be769cb1321d3dcf3cb25f3" 636 | integrity sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ== 637 | dependencies: 638 | get-func-name "^2.0.0" 639 | 640 | marked@^4.0.18: 641 | version "4.0.18" 642 | resolved "https://registry.yarnpkg.com/marked/-/marked-4.0.18.tgz#cd0ac54b2e5610cfb90e8fd46ccaa8292c9ed569" 643 | integrity sha512-wbLDJ7Zh0sqA0Vdg6aqlbT+yPxqLblpAZh1mK2+AO2twQkPywvvqQNfEPVwSSRjZ7dZcdeVBIAgiO7MMp3Dszw== 644 | 645 | minimatch@5.0.1: 646 | version "5.0.1" 647 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.0.1.tgz#fb9022f7528125187c92bd9e9b6366be1cf3415b" 648 | integrity sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g== 649 | dependencies: 650 | brace-expansion "^2.0.1" 651 | 652 | minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: 653 | version "3.1.2" 654 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" 655 | integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== 656 | dependencies: 657 | brace-expansion "^1.1.7" 658 | 659 | minimatch@^5.0.1: 660 | version "5.1.0" 661 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.0.tgz#1717b464f4971b144f6aabe8f2d0b8e4511e09c7" 662 | integrity sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg== 663 | dependencies: 664 | brace-expansion "^2.0.1" 665 | 666 | minimist@^1.2.0: 667 | version "1.2.6" 668 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" 669 | integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== 670 | 671 | mocha@^10.0.0: 672 | version "10.0.0" 673 | resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.0.0.tgz#205447d8993ec755335c4b13deba3d3a13c4def9" 674 | integrity sha512-0Wl+elVUD43Y0BqPZBzZt8Tnkw9CMUdNYnUsTfOM1vuhJVZL+kiesFYsqwBkEEuEixaiPe5ZQdqDgX2jddhmoA== 675 | dependencies: 676 | "@ungap/promise-all-settled" "1.1.2" 677 | ansi-colors "4.1.1" 678 | browser-stdout "1.3.1" 679 | chokidar "3.5.3" 680 | debug "4.3.4" 681 | diff "5.0.0" 682 | escape-string-regexp "4.0.0" 683 | find-up "5.0.0" 684 | glob "7.2.0" 685 | he "1.2.0" 686 | js-yaml "4.1.0" 687 | log-symbols "4.1.0" 688 | minimatch "5.0.1" 689 | ms "2.1.3" 690 | nanoid "3.3.3" 691 | serialize-javascript "6.0.0" 692 | strip-json-comments "3.1.1" 693 | supports-color "8.1.1" 694 | workerpool "6.2.1" 695 | yargs "16.2.0" 696 | yargs-parser "20.2.4" 697 | yargs-unparser "2.0.0" 698 | 699 | ms@2.1.2: 700 | version "2.1.2" 701 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" 702 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== 703 | 704 | ms@2.1.3: 705 | version "2.1.3" 706 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" 707 | integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== 708 | 709 | nanoid@3.3.3: 710 | version "3.3.3" 711 | resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25" 712 | integrity sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w== 713 | 714 | natural-compare@^1.4.0: 715 | version "1.4.0" 716 | resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" 717 | integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== 718 | 719 | normalize-path@^3.0.0, normalize-path@~3.0.0: 720 | version "3.0.0" 721 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" 722 | integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== 723 | 724 | once@^1.3.0: 725 | version "1.4.0" 726 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 727 | integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== 728 | dependencies: 729 | wrappy "1" 730 | 731 | optionator@^0.9.1: 732 | version "0.9.1" 733 | resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" 734 | integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== 735 | dependencies: 736 | deep-is "^0.1.3" 737 | fast-levenshtein "^2.0.6" 738 | levn "^0.4.1" 739 | prelude-ls "^1.2.1" 740 | type-check "^0.4.0" 741 | word-wrap "^1.2.3" 742 | 743 | p-limit@^3.0.2: 744 | version "3.1.0" 745 | resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" 746 | integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== 747 | dependencies: 748 | yocto-queue "^0.1.0" 749 | 750 | p-locate@^5.0.0: 751 | version "5.0.0" 752 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" 753 | integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== 754 | dependencies: 755 | p-limit "^3.0.2" 756 | 757 | parent-module@^1.0.0: 758 | version "1.0.1" 759 | resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" 760 | integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== 761 | dependencies: 762 | callsites "^3.0.0" 763 | 764 | path-exists@^4.0.0: 765 | version "4.0.0" 766 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" 767 | integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== 768 | 769 | path-is-absolute@^1.0.0: 770 | version "1.0.1" 771 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 772 | integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== 773 | 774 | path-key@^3.1.0: 775 | version "3.1.1" 776 | resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" 777 | integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== 778 | 779 | pathval@^1.1.1: 780 | version "1.1.1" 781 | resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" 782 | integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== 783 | 784 | picomatch@^2.0.4, picomatch@^2.2.1: 785 | version "2.3.1" 786 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" 787 | integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== 788 | 789 | prelude-ls@^1.2.1: 790 | version "1.2.1" 791 | resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" 792 | integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== 793 | 794 | punycode@^2.1.0: 795 | version "2.1.1" 796 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" 797 | integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== 798 | 799 | randombytes@^2.1.0: 800 | version "2.1.0" 801 | resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" 802 | integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== 803 | dependencies: 804 | safe-buffer "^5.1.0" 805 | 806 | readdirp@~3.6.0: 807 | version "3.6.0" 808 | resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" 809 | integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== 810 | dependencies: 811 | picomatch "^2.2.1" 812 | 813 | regexpp@^3.2.0: 814 | version "3.2.0" 815 | resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" 816 | integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== 817 | 818 | require-directory@^2.1.1: 819 | version "2.1.1" 820 | resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" 821 | integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== 822 | 823 | resolve-from@^4.0.0: 824 | version "4.0.0" 825 | resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" 826 | integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== 827 | 828 | rimraf@^3.0.2: 829 | version "3.0.2" 830 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" 831 | integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== 832 | dependencies: 833 | glob "^7.1.3" 834 | 835 | safe-buffer@^5.1.0: 836 | version "5.2.1" 837 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" 838 | integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== 839 | 840 | serialize-javascript@6.0.0: 841 | version "6.0.0" 842 | resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" 843 | integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== 844 | dependencies: 845 | randombytes "^2.1.0" 846 | 847 | shebang-command@^2.0.0: 848 | version "2.0.0" 849 | resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" 850 | integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== 851 | dependencies: 852 | shebang-regex "^3.0.0" 853 | 854 | shebang-regex@^3.0.0: 855 | version "3.0.0" 856 | resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" 857 | integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== 858 | 859 | string-width@^4.1.0, string-width@^4.2.0: 860 | version "4.2.3" 861 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" 862 | integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== 863 | dependencies: 864 | emoji-regex "^8.0.0" 865 | is-fullwidth-code-point "^3.0.0" 866 | strip-ansi "^6.0.1" 867 | 868 | strip-ansi@^6.0.0, strip-ansi@^6.0.1: 869 | version "6.0.1" 870 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" 871 | integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== 872 | dependencies: 873 | ansi-regex "^5.0.1" 874 | 875 | strip-json-comments@3.1.1, strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: 876 | version "3.1.1" 877 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" 878 | integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== 879 | 880 | supports-color@8.1.1: 881 | version "8.1.1" 882 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" 883 | integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== 884 | dependencies: 885 | has-flag "^4.0.0" 886 | 887 | supports-color@^7.1.0: 888 | version "7.2.0" 889 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" 890 | integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== 891 | dependencies: 892 | has-flag "^4.0.0" 893 | 894 | text-table@^0.2.0: 895 | version "0.2.0" 896 | resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" 897 | integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== 898 | 899 | to-regex-range@^5.0.1: 900 | version "5.0.1" 901 | resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" 902 | integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== 903 | dependencies: 904 | is-number "^7.0.0" 905 | 906 | type-check@^0.4.0, type-check@~0.4.0: 907 | version "0.4.0" 908 | resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" 909 | integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== 910 | dependencies: 911 | prelude-ls "^1.2.1" 912 | 913 | type-detect@^4.0.0, type-detect@^4.0.5: 914 | version "4.0.8" 915 | resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" 916 | integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== 917 | 918 | type-fest@^0.20.2: 919 | version "0.20.2" 920 | resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" 921 | integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== 922 | 923 | uri-js@^4.2.2: 924 | version "4.4.1" 925 | resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" 926 | integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== 927 | dependencies: 928 | punycode "^2.1.0" 929 | 930 | v8-compile-cache@^2.0.3: 931 | version "2.3.0" 932 | resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" 933 | integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== 934 | 935 | which@^2.0.1: 936 | version "2.0.2" 937 | resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" 938 | integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== 939 | dependencies: 940 | isexe "^2.0.0" 941 | 942 | word-wrap@^1.2.3: 943 | version "1.2.3" 944 | resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" 945 | integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== 946 | 947 | workerpool@6.2.1: 948 | version "6.2.1" 949 | resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343" 950 | integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw== 951 | 952 | wrap-ansi@^7.0.0: 953 | version "7.0.0" 954 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" 955 | integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== 956 | dependencies: 957 | ansi-styles "^4.0.0" 958 | string-width "^4.1.0" 959 | strip-ansi "^6.0.0" 960 | 961 | wrappy@1: 962 | version "1.0.2" 963 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 964 | integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== 965 | 966 | y18n@^5.0.5: 967 | version "5.0.8" 968 | resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" 969 | integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== 970 | 971 | yargs-parser@20.2.4: 972 | version "20.2.4" 973 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" 974 | integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== 975 | 976 | yargs-parser@^20.2.2: 977 | version "20.2.9" 978 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" 979 | integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== 980 | 981 | yargs-unparser@2.0.0: 982 | version "2.0.0" 983 | resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" 984 | integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== 985 | dependencies: 986 | camelcase "^6.0.0" 987 | decamelize "^4.0.0" 988 | flat "^5.0.2" 989 | is-plain-obj "^2.1.0" 990 | 991 | yargs@16.2.0: 992 | version "16.2.0" 993 | resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" 994 | integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== 995 | dependencies: 996 | cliui "^7.0.2" 997 | escalade "^3.1.1" 998 | get-caller-file "^2.0.5" 999 | require-directory "^2.1.1" 1000 | string-width "^4.2.0" 1001 | y18n "^5.0.5" 1002 | yargs-parser "^20.2.2" 1003 | 1004 | yocto-queue@^0.1.0: 1005 | version "0.1.0" 1006 | resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" 1007 | integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== 1008 | --------------------------------------------------------------------------------