├── .github └── FUNDING.yml ├── .gitignore ├── CONTRIBUTING.md ├── DOCUMENTATION.md ├── LICENSE ├── MIGRATION.md ├── README.md ├── bin └── git-stats ├── example └── index.js ├── lib └── index.js ├── out.html ├── package-lock.json ├── package.json └── scripts ├── init-git-post-commit └── migration └── 2.0.0.js /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: ionicabizau 2 | patreon: ionicabizau 3 | open_collective: ionicabizau 4 | custom: https://www.buymeacoffee.com/h96wwchmy -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *.swo 3 | *~ 4 | *.log 5 | node_modules 6 | *.env 7 | .DS_Store 8 | package-lock.json 9 | .bloggify/* 10 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # 🌟 Contributing 2 | 3 | Want to contribute to this project? Great! Please read these quick steps to streamline the process and avoid unnecessary tasks. ✨ 4 | 5 | ## 💬 Discuss Changes 6 | Start by opening an issue in the repository using the [bug tracker][1]. Describe your proposed contribution or the bug you've found. If relevant, include platform info and screenshots. 🖼️ 7 | 8 | Wait for feedback before proceeding unless the fix is straightforward, like a typo. 📝 9 | 10 | ## 🔧 Fixing Issues 11 | 12 | Fork the project and create a branch for your fix, naming it `some-great-feature` or `some-issue-fix`. Commit changes while following the [code style][2]. If the project has tests, add one. ✅ 13 | 14 | If a `package.json` or `bower.json` exists, add yourself to the `contributors` array; create it if it doesn't. 🙌 15 | 16 | ```json 17 | { 18 | "contributors": [ 19 | "Your Name (http://your.website)" 20 | ] 21 | } 22 | ``` 23 | 24 | ## 📬 Creating a Pull Request 25 | Open a pull request and reference the initial issue (e.g., *fixes #*). Provide a clear title and consider adding visual aids for clarity. 📊 26 | 27 | ## ⏳ Wait for Feedback 28 | Your contributions will be reviewed. If feedback is given, update your branch as needed, and the pull request will auto-update. 🔄 29 | 30 | ## 🎉 Everyone Is Happy! 31 | Your contributions will be merged, and everyone will appreciate your effort! 😄❤️ 32 | 33 | Thanks! 🤩 34 | 35 | [1]: /issues 36 | [2]: https://github.com/IonicaBizau/code-style -------------------------------------------------------------------------------- /DOCUMENTATION.md: -------------------------------------------------------------------------------- 1 | ## Documentation 2 | 3 | You can see below the API reference of this module. 4 | 5 | ### `GitStats(dataPath)` 6 | 7 | #### Params 8 | 9 | - **String** `dataPath`: Path to the data file. 10 | 11 | #### Return 12 | - **GitStats** The `GitStats` instance. 13 | 14 | ### `getConfig(callback)` 15 | Fetches the configuration object from file (`~/.git-stats-config.js`). 16 | 17 | #### Params 18 | 19 | - **Function** `callback`: The callback function. 20 | 21 | #### Return 22 | - **Object|Undefined** If no callback is provided, the configuration object will be returned. 23 | 24 | ### `initConfig(input, callback)` 25 | Inits the configuration field (`this.config`). 26 | 27 | #### Params 28 | 29 | - **Object|String** `input`: The path to a custom git-stats configuration file or the configuration object. 30 | - **Function** `callback`: The callback function. 31 | 32 | ### `record(data, callback)` 33 | Records a new commit. 34 | 35 | #### Params 36 | 37 | - **Object** `data`: The commit data containing: 38 | - `date` (String|Date): The date object or a string in a format that can be parsed. 39 | - `url` (String): The repository remote url. 40 | - `hash` (String): The commit hash. 41 | - `_data` (Object): If this field is provided, it should be the content of the git-stats data file as object. It will be modified in-memory and then returned. 42 | - `save` (Boolean): If `false`, the result will *not* be saved in the file. 43 | - **Function** `callback`: The callback function. 44 | 45 | #### Return 46 | - **GitStats** The `GitStats` instance. 47 | 48 | ### `record(data, callback)` 49 | removeCommit 50 | Deletes a specifc commit from the history. 51 | 52 | #### Params 53 | 54 | - **Object** `data`: The commit data containing: 55 | - `date` (String|Date): The date object or a string in a format that can be parsed. If not provided, the hash object will be searched in all dates. 56 | - `hash` (String): The commit hash. 57 | - `_data` (Object): If this field is provided, it should be the content of the git-stats data file as object. It will be modified in-memory and then returned. 58 | - `save` (Boolean): If `false`, the result will *not* be saved in the file. 59 | - **Function** `callback`: The callback function. 60 | 61 | #### Return 62 | - **GitStats** The `GitStats` instance. 63 | 64 | ### `get(callback)` 65 | Gets the git stats. 66 | 67 | #### Params 68 | 69 | - **Function** `callback`: The callback function. 70 | 71 | #### Return 72 | - **GitStats** The `GitStats` instance. 73 | 74 | ### `save(stats, callback)` 75 | Saves the provided stats. 76 | 77 | #### Params 78 | 79 | - **Object** `stats`: The stats to be saved. 80 | - **Function** `callback`: The callback function. 81 | 82 | #### Return 83 | - **GitStats** The `GitStats` instance. 84 | 85 | ### `iterateDays(data, callback)` 86 | Iterate through the days, calling the callback function on each day. 87 | 88 | #### Params 89 | 90 | - **Object** `data`: An object containing the following fields: 91 | - `start` (Moment): A `Moment` date object representing the start date (default: *an year ago*). 92 | - `end` (Moment): A `Moment` date object representing the end date (default: *now*). 93 | - `format` (String): The format of the date (default: `"MMM D, YYYY"`). 94 | - **Function** `callback`: The callback function called with the current day formatted (type: string) and the `Moment` date object. 95 | 96 | #### Return 97 | - **GitStats** The `GitStats` instance. 98 | 99 | ### `graph(data, callback)` 100 | Creates an object with the stats on the provided period (default: *last year*). 101 | 102 | #### Params 103 | 104 | - **Object** `data`: The object passed to the `iterateDays` method. 105 | - **Function** `callback`: The callback function. 106 | 107 | #### Return 108 | - **GitStats** The `GitStats` instance. 109 | 110 | ### `calendar(data, callback)` 111 | Creates the calendar data for the provided period (default: *last year*). 112 | 113 | #### Params 114 | 115 | - **Object** `data`: The object passed to the `graph` method. 116 | - **Function** `callback`: The callback function. 117 | 118 | #### Return 119 | - **GitStats** The `GitStats` instance. 120 | 121 | ### `ansiCalendar(options, callback)` 122 | Creates the ANSI contributions calendar. 123 | 124 | #### Params 125 | 126 | - **Object** `options`: The object passed to the `calendar` method. 127 | - **Function** `callback`: The callback function. 128 | 129 | #### Return 130 | - **GitStats** The `GitStats` instance. 131 | 132 | ### `authors(options, callback)` 133 | Creates an array with the authors of a git repository. 134 | 135 | #### Params 136 | 137 | - **String|Object** `options`: The repo path or an object containing the following fields: 138 | - `repo` (String): The repository path. 139 | - `start` (String): The start date. 140 | - `end` (String): The end date. 141 | - **Function** `callback`: The callback function. 142 | 143 | #### Return 144 | - **GitStats** The `GitStats` instance. 145 | 146 | ### `authorsPie(options, callback)` 147 | Creates the authors pie. 148 | 149 | #### Params 150 | 151 | - **String|Object** `options`: The repo path or an object containing the following fields: 152 | - `repo` (String): The repository path. 153 | - `radius` (Number): The pie radius. 154 | - `no_ansi` (Boolean): If `true`, the pie will not contain ansi characters. 155 | - `raw` (Boolean): If `true`, the raw JSON will be displayed. 156 | - **Function** `callback`: The callback function. 157 | 158 | #### Return 159 | - **GitStats** The `GitStats` instance. 160 | 161 | ### `globalActivity(options, callback)` 162 | Creates the global contributions calendar (all commits made by all committers). 163 | 164 | #### Params 165 | 166 | - **String|Object** `options`: The repo path or an object containing the following fields: 167 | - `repo` (String): The repository path. 168 | - `start` (String): The start date. 169 | - `end` (String): The end date. 170 | - `theme` (String|Object): The calendar theme. 171 | - `raw` (Boolean): If `true`, the raw JSON will be displayed. 172 | - **Function** `callback`: The callback function. 173 | 174 | #### Return 175 | - **GitStats** The `GitStats` instance. 176 | 177 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-25 Ionică Bizău (https://ionicabizau.net) 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 | -------------------------------------------------------------------------------- /MIGRATION.md: -------------------------------------------------------------------------------- 1 | ## Migration 2 | 3 | This document contains information about how to smoothly 4 | migrate the things from a version to another version. 5 | 6 | 7 | ### `1.x.x` to `2.x.x` 8 | 9 | The big change is the the data schema -- which should be migrated. 10 | 11 | The old `~/.git-stats` format was: 12 | 13 | ```json 14 | { 15 | "": { 16 | "": { 17 | "": "" 18 | } 19 | } 20 | } 21 | ``` 22 | 23 | In the new version, the remote url is not mandatory anymore. The new format is: 24 | 25 | ```json 26 | { 27 | "commits": { 28 | "": { 29 | "": 1 30 | } 31 | } 32 | } 33 | ``` 34 | 35 | This is supposed to change when users install the `2.x.x` versions. However, if 36 | the migration script fails, you can always run it manually: 37 | 38 | ```sh 39 | ./scripts/migration/2.0.0.js 40 | ``` 41 | 42 | This will modify the `~/.git-stats` file. 43 | 44 | When using `git-stats` as library, things changed too. The old way was: 45 | 46 | ```js 47 | var GitStats = require("git-stats"); 48 | 49 | GitStats.ansiCalendar(opts, fn); 50 | ``` 51 | 52 | In `2.x.x`, `GitStats` is a constructor. That allows us to create as many `git-stats` 53 | instances we want. 54 | 55 | ```js 56 | var GitStats = require("git-stats"); 57 | 58 | // Provide a custom data path 59 | var gs1 = new GitStats("path/to/some/data.json"); 60 | 61 | // Use the default (~/.git-stats) 62 | var gs2 = new GitStats(); 63 | ``` 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | [![git-stats](http://i.imgur.com/Q7TQYHx.png)](#) 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | # `$ git-stats` 23 | 24 | [![Support me on Patreon][badge_patreon]][patreon] [![Buy me a book][badge_amazon]][amazon] [![PayPal][badge_paypal_donate]][paypal-donations] [![Ask me anything](https://img.shields.io/badge/ask%20me-anything-1abc9c.svg)](https://github.com/IonicaBizau/ama) [![Version](https://img.shields.io/npm/v/git-stats.svg)](https://www.npmjs.com/package/git-stats) [![Downloads](https://img.shields.io/npm/dt/git-stats.svg)](https://www.npmjs.com/package/git-stats) [![Get help on Codementor](https://cdn.codementor.io/badges/get_help_github.svg)](https://www.codementor.io/@johnnyb?utm_source=github&utm_medium=button&utm_term=johnnyb&utm_campaign=github) 25 | 26 | Buy Me A Coffee 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | > Local git statistics including GitHub-like contributions calendars. 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | I'd be curious to see your calendar with all your commits. Ping me on Twitter ([**@IonicaBizau**](https://twitter.com/IonicaBizau)). :smile: Until then, here's my calendar: 43 | 44 | ![](http://i.imgur.com/PpM0i3v.png "") 45 | 46 | ## Contents 47 | 48 | 49 | - [Installation](#cloud-installation) 50 | - [Usage](#usage) 51 | 52 | - [Importing and deleting commits](#importing-and-deleting-commits) 53 | - [Importing all the commits from GitHub and BitBucket](#importing-all-the-commits-from-github-and-bitbucket) 54 | - [What about the GitHub Contributions calendar?](#what-about-the-github-contributions-calendar) 55 | 56 | - [Documentation](#memo-documentation) 57 | - [How to contribute](#yum-how-to-contribute) 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | ## :cloud: Installation 72 | 73 | You can install the package globally and use it as command line tool: 74 | 75 | 76 | ```sh 77 | # Install the package globally 78 | npm i -g git-stats 79 | 80 | # Initialize git hooks 81 | # This is for tracking the new commits 82 | curl -s https://raw.githubusercontent.com/IonicaBizau/git-stats/master/scripts/init-git-post-commit | bash 83 | ``` 84 | 85 | 86 | Then, run `git-stats --help` and see what the CLI tool can do. 87 | 88 | 89 | ``` 90 | $ git-stats --help 91 | Usage: git-stats [options] 92 | 93 | Local git statistics including GitHub-like contributions calendars. 94 | 95 | Options: 96 | -r, --raw Outputs a dump of the raw JSON data. 97 | -g, --global-activity Shows global activity calendar in the current 98 | repository. 99 | -d, --data Sets a custom data store file. 100 | -l, --light Enables the light theme. 101 | -n, --disable-ansi Forces the tool not to use ANSI styles. 102 | -A, --author Filter author related contributions in the current 103 | repository. 104 | -a, --authors Shows a pie chart with the author related 105 | contributions in the current repository. 106 | -u, --until Optional end date. 107 | -s, --since Optional start date. 108 | --record Records a new commit. Don't use this unless you are 109 | a mad scientist. If you are a developer just use 110 | this option as part of the module. 111 | -h, --help Displays this help. 112 | -v, --version Displays version information. 113 | 114 | Examples: 115 | $ git-stats # Default behavior (stats in the last year) 116 | $ git-stats -l # Light mode 117 | $ git-stats -s '1 January, 2012' # All the commits from 1 January 2012 to now 118 | $ git-stats -s '1 January, 2012' -u '31 December, 2012' # All the commits from 2012 119 | 120 | Your commit history is kept in ~/.git-stats by default. You can create 121 | ~/.git-stats-config.js to specify different defaults. 122 | 123 | Documentation can be found at https://github.com/IonicaBizau/git-stats. 124 | ``` 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | ## Usage 133 | 134 | ### Importing and deleting commits 135 | 136 | 137 | I know it's not nice to start your git commit calendar from scratch. That's why I created [`git-stats-importer`](https://github.com/IonicaBizau/git-stats-importer)–a tool which imports or deletes the commits from selected repositories. 138 | 139 | Check it out here: https://github.com/IonicaBizau/git-stats-importer 140 | 141 | The usage is simple: 142 | 143 | ```sh 144 | # Install the importer tool 145 | $ npm install -g git-stats-importer 146 | 147 | # Go to the repository you want to import 148 | $ cd path/to/my-repository 149 | 150 | # Import the commits 151 | $ git-stats-importer 152 | 153 | # ...or delete them if that's a dummy repository 154 | $ git-stats-importer --delete 155 | ``` 156 | 157 | ### Importing all the commits from GitHub and BitBucket 158 | 159 | 160 | Yes, that's also possible. I [built a tool which downloads and then imports all the commits you have pushed to GitHub and BitBucket](https://github.com/IonicaBizau/repository-downloader)! 161 | 162 | ```sh 163 | # Download the repository downloader 164 | $ git clone https://github.com/IonicaBizau/repository-downloader.git 165 | 166 | # Go to repository downloader 167 | $ cd repository-downloader 168 | 169 | # Install the dependencies 170 | $ npm install 171 | 172 | # Start downloading and importing 173 | $ ./start 174 | ``` 175 | 176 | ### What about the GitHub Contributions calendar? 177 | 178 | 179 | If you want to visualize the calendars that appear on GitHub profiles, you can do that using [`ghcal`](https://github.com/IonicaBizau/ghcal). 180 | 181 | ```sh 182 | # Install ghcal 183 | $ npm install -g ghcal 184 | 185 | # Check out @alysonla's contributions 186 | $ ghcal -u alysonla 187 | ``` 188 | 189 | 190 | For more detailed documentation, check out the repository: https://github.com/IonicaBizau/ghcal. 191 | 192 | If want to get even more GitHub stats in your terminal, you may want to try [`github-stats`](https://github.com/IonicaBizau/github-stats)--this is like `git-stats` but with data taken from GitHub. 193 | 194 | ## Using the configuration file 195 | 196 | 197 | You can tweak the git-stats behavior using a configuration file in your home directory: `~/.git-stats-config.js`. 198 | 199 | This file should export an object, like below (defaults are listed): 200 | 201 | ```js 202 | module.exports = { 203 | // "DARK", "LIGHT" or an object interpreted by IonicaBizau/node-git-stats-colors 204 | "theme": "DARK" 205 | 206 | // The file where the commit hashes will be stored 207 | , "path": "~/.git-stats" 208 | 209 | // [DEPRECATED] First day of the week https://github.com/IonicaBizau/git-stats/issues/121 210 | , first_day: "Sun" 211 | 212 | // This defaults to *one year ago* 213 | // It can be any parsable date 214 | , since: undefined 215 | 216 | // This defaults to *now* 217 | // It can be any parsable date 218 | , until: undefined 219 | 220 | // Don't show authors by default 221 | // If true, this will enable the authors pie 222 | , authors: false 223 | 224 | // No global activity by default 225 | // If true, this will enable the global activity calendar in the current project 226 | , global_activity: false 227 | }; 228 | ``` 229 | 230 | 231 | Since it's a js file, you can `require` any other modules there. 232 | 233 | ## Saving the data as HTML and images 234 | 235 | 236 | `git-stats --raw` outputs raw JSON format which can be consumed by other tools to generate results such as HTML files or images. 237 | 238 | [`git-stats-html`](https://github.com/IonicaBizau/git-stats-html) interprets the JSON data and generates an HTML file. Example: 239 | 240 | ```sh 241 | 242 | # Install git-stats-html 243 | 244 | npm install -g git-stats-html 245 | 246 | 247 | 248 | # Export the data from the last year (generate out.html) 249 | 250 | git-stats --raw | git-stats-html -o out.html 251 | 252 | 253 | 254 | # Export data since 2015 (save the results in out.html) 255 | 256 | git-stats --since '1 January 2015' --raw | ./bin/git-stats-html -o out.html --big 257 | 258 | ``` 259 | 260 | 261 | 262 | After we have the HTML file, we can generate an image file using [`pageres`](https://github.com/sindresorhus/pageres) by [**@sindresorhus**](https://github.com/sindresorhus/): 263 | 264 | ```sh 265 | 266 | # Install pageres 267 | 268 | npm install -g pageres-cli 269 | 270 | 271 | 272 | # Generate the image from HTML 273 | 274 | pageres out.html 775x250 275 | 276 | ``` 277 | 278 | 279 | 280 | ## Cross-platform compatibility 281 | 282 | 283 | `git-stats` is working fine in terminal emulators supporting ANSI styles. It should work fine on Linux and OS X. 284 | 285 | If you run `git-stats` to display graph on Windows, please use a terminal that can properly display ANSI colors. 286 | 287 | Cygwin Terminal is known to work, while Windows Command Prompt and Git Bash do not. Improvements are more than welcome! :dizzy: 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | ## :clipboard: Example 297 | 298 | 299 | 300 | Here is an example how to use this package as library. To install it locally, as library, you can use `npm install git-stats` (or `yarn add git-stats`): 301 | 302 | 303 | 304 | ```js 305 | // Dependencies 306 | var GitStats = require("git-stats"); 307 | 308 | // Create the GitStats instance 309 | var g1 = new GitStats(); 310 | 311 | // Display the ansi calendar 312 | g1.ansiCalendar({ 313 | theme: "DARK" 314 | }, function (err, data) { 315 | console.log(err || data); 316 | }); 317 | ``` 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | ## :question: Get Help 331 | 332 | There are few ways to get help: 333 | 334 | 335 | 336 | 1. Please [post questions on Stack Overflow](https://stackoverflow.com/questions/ask). You can open issues with questions, as long you add a link to your Stack Overflow question. 337 | 2. For bug reports and feature requests, open issues. :bug: 338 | 3. For direct and quick help, you can [use Codementor](https://www.codementor.io/johnnyb). :rocket: 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | ## :memo: Documentation 347 | 348 | For full API reference, see the [DOCUMENTATION.md][docs] file. 349 | 350 | 351 | 352 | 353 | 354 | 355 | ## :newspaper: Press Highlights 356 | 357 | - [*A GitHub-like contributions calendar, but locally, with all your git commits*, The Changelog](https://changelog.com/github-like-contributions-calendar-locally-git-commits/) 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | ## :yum: How to contribute 367 | Have an idea? Found a bug? See [how to contribute][contributing]. 368 | 369 | 370 | ## :sparkling_heart: Support my projects 371 | I open-source almost everything I can, and I try to reply to everyone needing help using these projects. Obviously, 372 | this takes time. You can integrate and use these projects in your applications *for free*! You can even change the source code and redistribute (even resell it). 373 | 374 | However, if you get some profit from this or just want to encourage me to continue creating stuff, there are few ways you can do it: 375 | 376 | 377 | - Starring and sharing the projects you like :rocket: 378 | - [![Buy me a book][badge_amazon]][amazon]—I love books! I will remember you after years if you buy me one. :grin: :book: 379 | - [![PayPal][badge_paypal]][paypal-donations]—You can make one-time donations via PayPal. I'll probably buy a ~~coffee~~ tea. :tea: 380 | - [![Support me on Patreon][badge_patreon]][patreon]—Set up a recurring monthly donation and you will get interesting news about what I'm doing (things that I don't share with everyone). 381 | - **Bitcoin**—You can send me bitcoins at this address (or scanning the code below): `1P9BRsmazNQcuyTxEqveUsnf5CERdq35V6` 382 | 383 | ![](https://i.imgur.com/z6OQI95.png) 384 | 385 | 386 | Thanks! :heart: 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | ## :dizzy: Where is this library used? 404 | If you are using this library in one of your projects, add it in this list. :sparkles: 405 | 406 | - `git-stats-fcc-importer` 407 | - `git-stats-importer` 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | ## :scroll: License 420 | 421 | [MIT][license] © [Ionică Bizău][website] 422 | 423 | 424 | 425 | 426 | 427 | 428 | [license]: /LICENSE 429 | [website]: https://ionicabizau.net 430 | [contributing]: /CONTRIBUTING.md 431 | [docs]: /DOCUMENTATION.md 432 | [badge_patreon]: https://ionicabizau.github.io/badges/patreon.svg 433 | [badge_amazon]: https://ionicabizau.github.io/badges/amazon.svg 434 | [badge_paypal]: https://ionicabizau.github.io/badges/paypal.svg 435 | [badge_paypal_donate]: https://ionicabizau.github.io/badges/paypal_donate.svg 436 | [patreon]: https://www.patreon.com/ionicabizau 437 | [amazon]: http://amzn.eu/hRo9sIZ 438 | [paypal-donations]: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=RVXDDLKKLQRJW 439 | -------------------------------------------------------------------------------- /bin/git-stats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | "use strict"; 3 | 4 | const Tilda = require("tilda") 5 | , GitStatsLib = require("..") 6 | , Ul = require("ul") 7 | , Moment = require("moment") 8 | , Logger = require("bug-killer") 9 | , Abs = require("abs") 10 | , Typpy = require("typpy") 11 | , Package = require("../package") 12 | , ReadJson = require("r-json") 13 | , IsThere = require("is-there") 14 | ; 15 | 16 | 17 | // Constants 18 | const GitStats = new GitStatsLib() 19 | , CONFIG_PATH = GitStatsLib.CONFIG_PATH 20 | , DEFAULT_CONFIG = GitStatsLib.DEFAULT_CONFIG 21 | ; 22 | 23 | try { 24 | GitStats.initConfig(); 25 | } catch (err) { 26 | if (err.code !== "MODULE_NOT_FOUND") { 27 | Logger.log("Failed to read the config file:\n" + err.stack, "warn"); 28 | } 29 | } 30 | 31 | // Configurations 32 | Moment.suppressDeprecationWarnings = true; 33 | 34 | new Tilda(`${__dirname}/../package.json`, { 35 | options: [ 36 | { 37 | opts: ["record"] 38 | , desc: "Records a new commit. Don't use this unless you are a mad scientist. If you are a developer just use this option as part of the module." 39 | , name: "data" 40 | } 41 | , { 42 | opts: ["s", "since"] 43 | , desc: "Optional start date." 44 | , name: "date" 45 | , default: GitStats.config.since 46 | } 47 | , { 48 | opts: ["u", "until"] 49 | , desc: "Optional end date." 50 | , name: "date" 51 | , default: GitStats.config.until 52 | } 53 | , { 54 | opts: ["a", "authors"] 55 | , desc: "Shows a pie chart with the author related contributions in the current repository." 56 | } 57 | ,{ 58 | opts: ["A", "author"] 59 | , desc: "Filter author related contributions in the current repository." 60 | } 61 | , { 62 | opts: ["n", "disable-ansi"] 63 | , desc: "Forces the tool not to use ANSI styles." 64 | } 65 | , { 66 | opts: ["l", "light"] 67 | , desc: "Enables the light theme." 68 | } 69 | , { 70 | opts: ["d", "data"] 71 | , desc: "Sets a custom data store file." 72 | , name: "path" 73 | , default: GitStats.config.path 74 | } 75 | , { 76 | opts: ["g", "global-activity"] 77 | , desc: "Shows global activity calendar in the current repository." 78 | } 79 | , { 80 | opts: ["r", "raw"] 81 | , desc: "Outputs a dump of the raw JSON data." 82 | } 83 | ] 84 | , examples: [ 85 | "git-stats # Default behavior (stats in the last year)" 86 | , "git-stats -l # Light mode" 87 | , "git-stats -s '1 January, 2012' # All the commits from 1 January 2012 to now" 88 | , "git-stats -s '1 January, 2012' -u '31 December, 2012' # All the commits from 2012" 89 | ] 90 | , notes: "Your commit history is kept in ~/.git-stats by default. You can create ~/.git-stats-config.js to specify different defaults." 91 | }).main(action => { 92 | 93 | let recordOpt = action.options.record 94 | , sinceDateOpt = action.options.since 95 | , untilDateOpt = action.options.until 96 | , authorsOpt = action.options.authors 97 | , noAnsiOpt = action.options.disableAnsi 98 | , lightOpt = action.options.light 99 | , dataPathOpt = action.options.data 100 | , globalActivityOpt = action.options.globalActivity 101 | , rawOpt = action.options.raw 102 | , authorOpt = action.options.author 103 | ; 104 | 105 | let options = {}; 106 | 107 | if(GitStats.config.path) { 108 | dataPathOpt.is_provided = true; 109 | } 110 | 111 | if (GitStats.config.authors) { 112 | authorsOpt.is_provided = true; 113 | } 114 | 115 | if (GitStats.config.global_activity) { 116 | globalActivityOpt.is_provided = true; 117 | } 118 | 119 | // Handle data path 120 | if (dataPathOpt.is_provided) { 121 | if (IsThere(dataPathOpt.value)) { 122 | GitStats.path = Abs(dataPathOpt.value); 123 | GitStats.config.data_path = GitStats.path; 124 | } 125 | else { 126 | Logger.log("Cannot find the the specified data path file.", "warn"); 127 | } 128 | } 129 | 130 | // --record 131 | if (recordOpt.is_provided) { 132 | try { 133 | options = JSON.parse(recordOpt.value.replace(/^\"|\"$/g, "")); 134 | } catch (e) { 135 | Logger.log(e, "error"); 136 | return process.exit(1); 137 | } 138 | 139 | return GitStats.record(options, function (err) { 140 | if (err) { return Logger.log(err, "error"); } 141 | process.exit(0); 142 | }); 143 | } 144 | 145 | // Create the options 146 | options = { 147 | start: sinceDateOpt.value ? Moment(sinceDateOpt.value) : Moment().subtract(1, "years") 148 | , end: untilDateOpt.value ? Moment(untilDateOpt.value) : Moment() 149 | , raw: rawOpt.is_provided 150 | }; 151 | 152 | // Validate the dates 153 | if (!options.start || !options.start.isValid()) { 154 | options.start = Moment().subtract(1, "years"); 155 | Logger.log("Invalid start date. Using default instead (" + options.start.format("LL") + ").", "warn"); 156 | } 157 | 158 | // Handle time range options 159 | if (!options.end || !options.end.isValid()) { 160 | options.end = Moment(); 161 | Logger.log("Invalid end date. Using default instead (" + options.end.format("LL") + ").", "warn"); 162 | } 163 | 164 | // Add the repo path 165 | if (authorsOpt.is_provided || globalActivityOpt.is_provided) { 166 | options.repo = process.cwd(); 167 | } 168 | 169 | // Add the author opt 170 | if(authorOpt.is_provided){ 171 | options.author = authorOpt.value 172 | } 173 | 174 | // Handle authors 175 | if (authorsOpt.is_provided) { 176 | options.no_ansi = noAnsiOpt.is_provided; 177 | options.radius = (process.stdout.rows / 2) - 4; 178 | } 179 | 180 | if (!authorsOpt.is_provided || globalActivityOpt.is_provided) { 181 | // This can be a string or an object 182 | if (/^object|string$/.test(Typpy(GitStats.config.theme)) && !noAnsiOpt.is_provided && !lightOpt.is_provided) { 183 | options.theme = GitStats.config.theme; 184 | if (typeof GitStats.config.theme === "string") { 185 | if (!/^DARK|LIGHT$/.test(options.theme)) { 186 | options.theme = null; 187 | } 188 | } 189 | } else { 190 | options.theme = noAnsiOpt.is_provided ? null 191 | : lightOpt.is_provided ? "LIGHT": "DARK" 192 | ; 193 | } 194 | } 195 | 196 | function display (err, data) { 197 | if (err) { return Logger.log(err, "error"); } 198 | if (typeof data !== "string") { 199 | data = JSON.stringify(data); 200 | } 201 | process.stdout.write(data + "\n"); 202 | } 203 | 204 | if (globalActivityOpt.is_provided) { 205 | return GitStats.globalActivity(options, display); 206 | } 207 | 208 | // Show the graphs 209 | GitStats[authorsOpt.is_provided ? "authorsPie" : "ansiCalendar"](options, display); 210 | }); 211 | -------------------------------------------------------------------------------- /example/index.js: -------------------------------------------------------------------------------- 1 | // Dependencies 2 | var GitStats = require("../lib"); 3 | 4 | // Create the GitStats instance 5 | var g1 = new GitStats(); 6 | 7 | // Display the ansi calendar 8 | g1.ansiCalendar({ 9 | theme: "DARK" 10 | }, function (err, data) { 11 | console.log(err || data); 12 | }); 13 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const Ul = require("ul") 4 | , Abs = require("abs") 5 | , ReadJson = require("r-json") 6 | , WriteJson = require("w-json") 7 | , Moment = require("moment") 8 | , Gry = require("gry") 9 | , IsThere = require("is-there") 10 | , CliPie = require("cli-pie") 11 | , CliGhCal = require("cli-gh-cal") 12 | , GitLogParser = require("gitlog-parser").parse 13 | , ChildProcess = require("child_process") 14 | , Deffy = require("deffy") 15 | , Typpy = require("typpy") 16 | , Spawn = ChildProcess.spawn 17 | , IterateObject = require("iterate-object") 18 | ; 19 | 20 | // Constants 21 | const DATE_FORMAT = "MMM D, YYYY" 22 | , DEFAULT_STORE = Abs("~/.git-stats") 23 | , DEFAULT_DATA = { 24 | commits: {} 25 | } 26 | , CONFIG_PATH = Abs("~/.git-stats-config.js") 27 | ; 28 | 29 | 30 | class GitStats { 31 | /** 32 | * GitStats 33 | * 34 | * @name GitStats 35 | * @function 36 | * @param {String} dataPath Path to the data file. 37 | * @return {GitStats} The `GitStats` instance. 38 | */ 39 | constructor (dataPath) { 40 | this.path = Abs(Deffy(dataPath, DEFAULT_STORE)); 41 | this.config = {}; 42 | } 43 | 44 | /** 45 | * getConfig 46 | * Fetches the configuration object from file (`~/.git-stats-config.js`). 47 | * 48 | * @name getConfig 49 | * @function 50 | * @param {Function} callback The callback function. 51 | * @return {Object|Undefined} If no callback is provided, the configuration object will be returned. 52 | */ 53 | getConfig (callback) { 54 | let data = {} 55 | , err = null 56 | ; 57 | 58 | try { 59 | data = require(CONFIG_PATH); 60 | } catch (err) { 61 | if (err.code === "MODULE_NOT_FOUND") { 62 | err = null; 63 | data = {}; 64 | } 65 | } 66 | 67 | if (callback) { 68 | return callback(err, data); 69 | } else { 70 | if (err) { 71 | throw err; 72 | } 73 | } 74 | 75 | return data; 76 | } 77 | 78 | /** 79 | * initConfig 80 | * Inits the configuration field (`this.config`). 81 | * 82 | * @name initConfig 83 | * @function 84 | * @param {Object|String} input The path to a custom git-stats configuration file or the configuration object. 85 | * @param {Function} callback The callback function. 86 | */ 87 | initConfig (input, callback) { 88 | 89 | const self = this; 90 | 91 | if (Typpy(input, Function)) { 92 | callback = input; 93 | input = null; 94 | } 95 | 96 | input = input || CONFIG_PATH; 97 | 98 | // Handle object input 99 | if (Typpy(input, Object)) { 100 | this.config = Ul.deepMerge(input, GitStats.DEFAULT_CONFIG); 101 | callback && callback(null, this.config); 102 | return this.config; 103 | } 104 | 105 | if (callback) { 106 | this.getConfig(function (err, data) { 107 | if (err) { return callback(err); } 108 | self.initConfig(data, callback); 109 | }); 110 | } else { 111 | this.initConfig(this.getConfig()); 112 | } 113 | } 114 | 115 | /** 116 | * record 117 | * Records a new commit. 118 | * 119 | * @name record 120 | * @function 121 | * @param {Object} data The commit data containing: 122 | * 123 | * - `date` (String|Date): The date object or a string in a format that can be parsed. 124 | * - `url` (String): The repository remote url. 125 | * - `hash` (String): The commit hash. 126 | * - `_data` (Object): If this field is provided, it should be the content of the git-stats data file as object. It will be modified in-memory and then returned. 127 | * - `save` (Boolean): If `false`, the result will *not* be saved in the file. 128 | * 129 | * @param {Function} callback The callback function. 130 | * @return {GitStats} The `GitStats` instance. 131 | */ 132 | record (data, callback) { 133 | 134 | const self = this; 135 | 136 | // Validate data 137 | callback = callback || function (err) { if (err) throw err; }; 138 | data = Object(data); 139 | 140 | if (typeof data.date === "string") { 141 | data.date = new Moment(new Date(data.date)); 142 | } 143 | 144 | if (!/^moment|date$/.test(Typpy(data.date))) { 145 | callback(new Error("The date field should be a string or a date object.")); 146 | return GitStats; 147 | } else if (Typpy(data.date, Date)) { 148 | data.date = Moment(data.date); 149 | } 150 | 151 | if (typeof data.hash !== "string" || !data.hash) { 152 | callback(new Error("Invalid hash.")); 153 | return GitStats; 154 | } 155 | 156 | // This is not used, but remains here just in case we need 157 | // it in the future 158 | if (typeof data.url !== "string" || !data.url) { 159 | delete data.url; 160 | } 161 | 162 | function modify (err, stats) { 163 | 164 | const commits = stats.commits 165 | , day = data.date.format(DATE_FORMAT) 166 | , today = commits[day] = Object(commits[day]) 167 | ; 168 | 169 | today[data.hash] = 1; 170 | 171 | if (data.save === false) { 172 | callback(null, stats); 173 | } else { 174 | self.save(stats, callback); 175 | } 176 | 177 | return stats; 178 | } 179 | 180 | // Check if we have input data 181 | if (data._data) { 182 | return modify(null, data._data); 183 | } else { 184 | // Get stats 185 | self.get(modify); 186 | } 187 | 188 | return self; 189 | } 190 | 191 | /** 192 | * removeCommit 193 | * Deletes a specifc commit from the history. 194 | * 195 | * @name record 196 | * @function 197 | * @param {Object} data The commit data containing: 198 | * 199 | * - `date` (String|Date): The date object or a string in a format that can be parsed. If not provided, the hash object will be searched in all dates. 200 | * - `hash` (String): The commit hash. 201 | * - `_data` (Object): If this field is provided, it should be the content of the git-stats data file as object. It will be modified in-memory and then returned. 202 | * - `save` (Boolean): If `false`, the result will *not* be saved in the file. 203 | * 204 | * @param {Function} callback The callback function. 205 | * @return {GitStats} The `GitStats` instance. 206 | */ 207 | removeCommit (data, callback) { 208 | 209 | const self = this; 210 | 211 | // Validate data 212 | callback = callback || function (err) { if (err) throw err; }; 213 | data = Object(data); 214 | 215 | if (typeof data.date === "string") { 216 | data.date = new Moment(new Date(data.date)); 217 | } 218 | 219 | if (!/^moment|date$/.test(Typpy(data.date))) { 220 | data.date = null; 221 | } else if (Typpy(data.date, Date)) { 222 | data.date = Moment(data.date); 223 | } 224 | 225 | if (typeof data.hash !== "string" || !data.hash) { 226 | callback(new Error("Invalid hash.")); 227 | return GitStats; 228 | } 229 | 230 | function modify (err, stats) { 231 | 232 | if (err) { return callback(err); } 233 | if (!data.date) { 234 | IterateObject(stats.commits, function (todayObj) { 235 | delete todayObj[data.hash]; 236 | }); 237 | } else { 238 | const commits = stats.commits 239 | , day = data.date.format(DATE_FORMAT) 240 | , today = commits[day] = Object(commits[day]) 241 | ; 242 | 243 | delete today[data.hash]; 244 | } 245 | 246 | if (data.save === false) { 247 | callback(null, stats); 248 | } else { 249 | self.save(stats, callback); 250 | } 251 | 252 | return stats; 253 | } 254 | 255 | // Check if we have input data 256 | if (data._data) { 257 | return modify(null, data._data); 258 | } else { 259 | // Get stats 260 | self.get(modify); 261 | } 262 | 263 | return self; 264 | } 265 | 266 | /** 267 | * get 268 | * Gets the git stats. 269 | * 270 | * @name get 271 | * @function 272 | * @param {Function} callback The callback function. 273 | * @return {GitStats} The `GitStats` instance. 274 | */ 275 | get (callback) { 276 | const self = this; 277 | ReadJson(self.path, function (err, data) { 278 | 279 | if (err && err.code === "ENOENT") { 280 | return self.save(DEFAULT_DATA, function (err) { 281 | callback(err, DEFAULT_DATA); 282 | }); 283 | } 284 | 285 | if (err) { return callback(err); } 286 | callback(null, data); 287 | }); 288 | return self; 289 | } 290 | 291 | /** 292 | * save 293 | * Saves the provided stats. 294 | * 295 | * @name save 296 | * @function 297 | * @param {Object} stats The stats to be saved. 298 | * @param {Function} callback The callback function. 299 | * @return {GitStats} The `GitStats` instance. 300 | */ 301 | save (stats, callback) { 302 | WriteJson(this.path, stats, callback); 303 | return this; 304 | } 305 | 306 | /** 307 | * iterateDays 308 | * Iterate through the days, calling the callback function on each day. 309 | * 310 | * @name iterateDays 311 | * @function 312 | * @param {Object} data An object containing the following fields: 313 | * 314 | * - `start` (Moment): A `Moment` date object representing the start date (default: *an year ago*). 315 | * - `end` (Moment): A `Moment` date object representing the end date (default: *now*). 316 | * - `format` (String): The format of the date (default: `"MMM D, YYYY"`). 317 | * 318 | * @param {Function} callback The callback function called with the current day formatted (type: string) and the `Moment` date object. 319 | * @return {GitStats} The `GitStats` instance. 320 | */ 321 | iterateDays (data, callback) { 322 | 323 | if (typeof data === "function") { 324 | callback = data; 325 | data = undefined; 326 | } 327 | 328 | // Merge the defaults 329 | data.end = data.end || Moment(); 330 | data.start = data.start || Moment().subtract(1, "years"); 331 | data.format = data.format || DATE_FORMAT; 332 | 333 | let start = new Moment(data.start.format(DATE_FORMAT), DATE_FORMAT) 334 | , end = new Moment(data.end.format(DATE_FORMAT), DATE_FORMAT) 335 | , tomrrow = Moment(end.format(DATE_FORMAT), DATE_FORMAT).add(1, "days") 336 | , endStr = tomrrow.format(DATE_FORMAT) 337 | , cDay = null 338 | ; 339 | 340 | while (start.format(DATE_FORMAT) !== endStr) { 341 | cDay = start.format(data.format); 342 | callback(cDay, start); 343 | start.add(1, "days"); 344 | } 345 | 346 | return this; 347 | } 348 | 349 | /** 350 | * graph 351 | * Creates an object with the stats on the provided period (default: *last year*). 352 | * 353 | * @name graph 354 | * @function 355 | * @param {Object} data The object passed to the `iterateDays` method. 356 | * @param {Function} callback The callback function. 357 | * @return {GitStats} The `GitStats` instance. 358 | */ 359 | graph (data, callback) { 360 | 361 | if (typeof data === "function") { 362 | callback = data; 363 | data = undefined; 364 | } 365 | 366 | const self = this; 367 | 368 | // Get commits 369 | self.get(function (err, stats) { 370 | if (err) { return callback(err); } 371 | 372 | let cDayObj = null 373 | , year = {} 374 | ; 375 | 376 | // Iterate days 377 | self.iterateDays(data, function (cDay) { 378 | cDayObj = Object(stats.commits[cDay]); 379 | cDayObj = year[cDay] = { 380 | _: cDayObj 381 | , c: Object.keys(cDayObj).length 382 | }; 383 | }); 384 | 385 | callback(null, year); 386 | }); 387 | 388 | return self; 389 | } 390 | 391 | /** 392 | * calendar 393 | * Creates the calendar data for the provided period (default: *last year*). 394 | * 395 | * @name calendar 396 | * @function 397 | * @param {Object} data The object passed to the `graph` method. 398 | * @param {Function} callback The callback function. 399 | * @return {GitStats} The `GitStats` instance. 400 | */ 401 | calendar (data, callback) { 402 | 403 | const self = this; 404 | 405 | self.graph(data, function (err, graph) { 406 | if (err) { return callback(err); } 407 | 408 | let cal = { total: 0, days: {}, cStreak: 0, lStreak: 0, max: 0 } 409 | , cDay = null 410 | , days = Object.keys(graph) 411 | , levels = null 412 | , cLevel = 0 413 | ; 414 | 415 | days.forEach(function (c) { 416 | cDay = graph[c]; 417 | cal.total += cDay.c; 418 | if (cDay.c > cal.max) { 419 | cal.max = cDay.c; 420 | } 421 | 422 | if (cDay.c > 0) { 423 | if (++cal.cStreak > cal.lStreak) { 424 | cal.lStreak = cal.cStreak; 425 | } 426 | } else { 427 | cal.cStreak = 0; 428 | } 429 | }); 430 | 431 | levels = cal.max / (LEVELS.length * 2); 432 | days.forEach(function (c) { 433 | cDay = graph[c]; 434 | cal.days[c] = { 435 | c: cDay.c 436 | , level: !levels 437 | ? 0 : (cLevel = Math.round(cDay.c / levels)) >= 4 438 | ? 4 : !cLevel && cDay.c > 0 ? 1 : cLevel 439 | }; 440 | }); 441 | 442 | callback(null, cal); 443 | }); 444 | return self; 445 | } 446 | 447 | /** 448 | * ansiCalendar 449 | * Creates the ANSI contributions calendar. 450 | * 451 | * @name ansiCalendar 452 | * @function 453 | * @param {Object} options The object passed to the `calendar` method. 454 | * @param {Function} callback The callback function. 455 | * @return {GitStats} The `GitStats` instance. 456 | */ 457 | ansiCalendar (options, callback) { 458 | 459 | if (typeof options === "function") { 460 | callback = options; 461 | options = undefined; 462 | } 463 | 464 | const self = this; 465 | 466 | self.graph(options, function (err, graph) { 467 | let cal = [] 468 | , data = { 469 | theme: options.theme 470 | , start: options.start 471 | , end: options.end 472 | , firstDay: options.firstDay // [DEPRECATED] https://github.com/IonicaBizau/git-stats/issues/121 473 | , cal: cal 474 | , raw: options.raw 475 | } 476 | ; 477 | 478 | self.iterateDays(options, function (cDay) { 479 | const cDayObj = graph[cDay]; 480 | if (!cDayObj) { return; } 481 | cal.push([cDay, cDayObj.c]); 482 | }); 483 | 484 | callback(null, CliGhCal(cal, data)); 485 | }); 486 | 487 | return self; 488 | } 489 | 490 | /** 491 | * authors 492 | * Creates an array with the authors of a git repository. 493 | * 494 | * @name authors 495 | * @function 496 | * @param {String|Object} options The repo path or an object containing the following fields: 497 | * 498 | * - `repo` (String): The repository path. 499 | * - `start` (String): The start date. 500 | * - `end` (String): The end date. 501 | * 502 | * @param {Function} callback The callback function. 503 | * @return {GitStats} The `GitStats` instance. 504 | */ 505 | authors (options, callback) { 506 | const repo = new Gry(options.repo); 507 | repo.exec(['shortlog', '-s', '-n', '--all', '--since', options.start.toString(), '--until', options.end.toString()], function (err, stdout) { 508 | if (err) { return callback(err); } 509 | const lines = stdout.split("\n"); 510 | const pieData = stdout.split("\n").map(function (c) { 511 | const splits = c.split("\t").map(function (cc) { 512 | return cc.trim(); 513 | }); 514 | return { 515 | value: parseInt(splits[0]) 516 | , label: splits[1] 517 | }; 518 | }); 519 | callback(null, pieData); 520 | }); 521 | return this; 522 | } 523 | 524 | /** 525 | * authorsPie 526 | * Creates the authors pie. 527 | * 528 | * @name authorsPie 529 | * @function 530 | * @param {String|Object} options The repo path or an object containing the following fields: 531 | * 532 | * - `repo` (String): The repository path. 533 | * - `radius` (Number): The pie radius. 534 | * - `no_ansi` (Boolean): If `true`, the pie will not contain ansi characters. 535 | * - `raw` (Boolean): If `true`, the raw JSON will be displayed. 536 | * 537 | * @param {Function} callback The callback function. 538 | * @return {GitStats} The `GitStats` instance. 539 | */ 540 | authorsPie (options, callback) { 541 | 542 | if (typeof options === "string") { 543 | options = { 544 | repo: options 545 | }; 546 | } 547 | 548 | options = Ul.merge(options, { 549 | radius: process.stdout.rows / 2 || 20 550 | }); 551 | 552 | if (!IsThere(options.repo)) { 553 | return callback(new Error("The repository folder doesn't exist.")); 554 | } 555 | 556 | let self = this 557 | , repo = new Gry(options.repo) 558 | , pie = null 559 | , pieData = [] 560 | ; 561 | 562 | self.authors(options, function (err, authors) { 563 | const maxAuthors = 2 * options.radius; 564 | if (err) { return callback(err); } 565 | if (authors.length > maxAuthors) { 566 | let others = { 567 | value: authors.slice(maxAuthors).reduce(function (a, b) { 568 | return a + b.value; 569 | }, 0) 570 | , label: "Others" 571 | }; 572 | authors = authors.slice(0, maxAuthors); 573 | authors.push(others); 574 | } 575 | 576 | let data = { 577 | legend: true 578 | , flat: true 579 | , no_ansi: options.no_ansi 580 | , authors: authors 581 | }; 582 | 583 | callback(null, options.raw ? data : new CliPie(options.radius, authors, data).toString()); 584 | }); 585 | 586 | return self; 587 | } 588 | 589 | /** 590 | * globalActivity 591 | * Creates the global contributions calendar (all commits made by all committers). 592 | * 593 | * @name globalActivity 594 | * @function 595 | * @param {String|Object} options The repo path or an object containing the following fields: 596 | * 597 | * - `repo` (String): The repository path. 598 | * - `start` (String): The start date. 599 | * - `end` (String): The end date. 600 | * - `theme` (String|Object): The calendar theme. 601 | * - `raw` (Boolean): If `true`, the raw JSON will be displayed. 602 | * 603 | * @param {Function} callback The callback function. 604 | * @return {GitStats} The `GitStats` instance. 605 | */ 606 | globalActivity (options, callback) { 607 | 608 | if (typeof options === "string") { 609 | options = { 610 | repo: options 611 | }; 612 | } 613 | 614 | options.repo = Abs(options.repo); 615 | 616 | if (!IsThere(options.repo)) { 617 | return callback(new Error("The repository folder doesn't exist.")); 618 | } 619 | 620 | let commits = {} 621 | , today = null 622 | , cal = [] 623 | ; 624 | 625 | let logArgs = ["log","--since", options.start.format(DATE_FORMAT), "--until", options.end.format(DATE_FORMAT)] 626 | if(options.author){ 627 | logArgs = logArgs.concat(["--author", options.author]) 628 | } 629 | 630 | GitLogParser(Spawn("git",logArgs , { cwd: options.repo }).stdout).on("commit", function(commit) { 631 | if (!commit) { return; } 632 | today = Moment(commit.date).format(DATE_FORMAT); 633 | commits[today] = commits[today] || 0; 634 | ++commits[today]; 635 | }).on("error", function (err) { 636 | callback(err); 637 | }).on("finish", function () { 638 | Object.keys(commits).forEach(function (c) { 639 | cal.push([c, commits[c]]) 640 | }); 641 | let data = { 642 | theme: options.theme 643 | , start: options.start 644 | , end: options.end 645 | , cal: cal 646 | , raw: options.raw 647 | }; 648 | callback(null, CliGhCal(cal, data)); 649 | }); 650 | 651 | return this; 652 | } 653 | } 654 | 655 | // Defaults 656 | GitStats.CONFIG_PATH = CONFIG_PATH 657 | GitStats.DEFAULT_CONFIG = { 658 | // Dark theme by default 659 | theme: "DARK" 660 | 661 | // This defaults in library 662 | , path: undefined 663 | 664 | // [DEPRECATED] https://github.com/IonicaBizau/git-stats/issues/121 665 | // This defaults in cli-gh-cal 666 | , first_day: undefined 667 | 668 | // This defaults to *one year ago* 669 | , since: undefined 670 | 671 | // This defaults to *now* 672 | , until: undefined 673 | 674 | // Don't show authors by default 675 | , authors: false 676 | 677 | // No global activity by default 678 | , global_activity: false 679 | }; 680 | 681 | module.exports = GitStats; 682 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "git-stats", 3 | "version": "3.2.1", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "git-stats", 9 | "version": "3.2.1", 10 | "hasInstallScript": true, 11 | "license": "MIT", 12 | "dependencies": { 13 | "abs": "^1.0.0", 14 | "bug-killer": "^4.0.0", 15 | "cli-gh-cal": "^1.4.0", 16 | "cli-pie": "^2.0.0", 17 | "deffy": "^2.2.2", 18 | "gitlog-parser": "0.0.4", 19 | "gry": "^6.1.0", 20 | "is-there": "^4.0.0", 21 | "iterate-object": "^1.1.0", 22 | "moment": "^2.29.3", 23 | "r-json": "^1.0.0", 24 | "tilda": "^4.3.3", 25 | "typpy": "^2.1.0", 26 | "ul": "^5.0.0", 27 | "w-json": "^1.0.0" 28 | }, 29 | "bin": { 30 | "git-stats": "bin/git-stats" 31 | } 32 | }, 33 | "node_modules/abs": { 34 | "version": "1.3.14", 35 | "resolved": "https://registry.npmjs.org/abs/-/abs-1.3.14.tgz", 36 | "integrity": "sha512-PrS26IzwKLWwuURpiKl8wRmJ2KdR/azaVrLEBWG/TALwT20Y7qjtYp1qcMLHA4206hBHY5phv3w4pjf9NPv4Vw==", 37 | "dependencies": { 38 | "ul": "^5.0.0" 39 | } 40 | }, 41 | "node_modules/add-subtract-date": { 42 | "version": "1.0.15", 43 | "resolved": "https://registry.npmjs.org/add-subtract-date/-/add-subtract-date-1.0.15.tgz", 44 | "integrity": "sha512-MiL4wnMyM999meyCrSA3LME9uZ/b5ptSd0ACDVUoTfutFwvkMyIN7nG7gjrU56WEk5RlFLBghabcgdYwY8s+nQ==" 45 | }, 46 | "node_modules/ansi-parser": { 47 | "version": "3.2.10", 48 | "resolved": "https://registry.npmjs.org/ansi-parser/-/ansi-parser-3.2.10.tgz", 49 | "integrity": "sha512-CGKGIbd678lm15IXJXI1cTyOVAnMQw0jES+klW/yIc+GzYccsYanLMhczPIIj2hE64B79g75QfiuWrEWd6nJdg==" 50 | }, 51 | "node_modules/ansi-regex": { 52 | "version": "4.1.1", 53 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", 54 | "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", 55 | "engines": { 56 | "node": ">=6" 57 | } 58 | }, 59 | "node_modules/ansi-styles": { 60 | "version": "3.2.1", 61 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 62 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 63 | "dependencies": { 64 | "color-convert": "^1.9.0" 65 | }, 66 | "engines": { 67 | "node": ">=4" 68 | } 69 | }, 70 | "node_modules/ansy": { 71 | "version": "1.0.15", 72 | "resolved": "https://registry.npmjs.org/ansy/-/ansy-1.0.15.tgz", 73 | "integrity": "sha512-mQyNSn58HN7aEthofkap0hn8jg7/5SJWrB0ypExgcECOwLppc0njH+QBA9X5VMiEN9SM0JlFZWJQGycxxInAqg==", 74 | "dependencies": { 75 | "ansi-styles": "^3.0.0", 76 | "custom-return": "^1.0.0", 77 | "supports-color": "^3.1.2", 78 | "ul": "^5.2.1" 79 | } 80 | }, 81 | "node_modules/arrs-to-obj": { 82 | "version": "1.0.12", 83 | "resolved": "https://registry.npmjs.org/arrs-to-obj/-/arrs-to-obj-1.0.12.tgz", 84 | "integrity": "sha512-348sGggQcNrSVF4J009QXjfb5XrxwTw+tjMoOLIUrfRqxmSUf9W/U9hX3XdR5St/sX2Tc994WepBfRjr2BYg1g==" 85 | }, 86 | "node_modules/auto-parse": { 87 | "version": "1.8.0", 88 | "resolved": "https://registry.npmjs.org/auto-parse/-/auto-parse-1.8.0.tgz", 89 | "integrity": "sha512-Uri4uC+K5cSi5hjM4snFrqPrjqUpwxeSW5EMTPvN7Ju3PlDzmXXDr5tjdzxPvvwgT3J7bmMDJ3Rm625nbrc72A==", 90 | "dependencies": { 91 | "typpy": "2.3.11" 92 | } 93 | }, 94 | "node_modules/auto-parse/node_modules/typpy": { 95 | "version": "2.3.11", 96 | "resolved": "https://registry.npmjs.org/typpy/-/typpy-2.3.11.tgz", 97 | "integrity": "sha512-Jh/fykZSaxeKO0ceMAs6agki9T5TNA9kiIR6fzKbvafKpIw8UlNlHhzuqKyi5lfJJ5VojJOx9tooIbyy7vHV/g==", 98 | "dependencies": { 99 | "function.name": "^1.0.3" 100 | } 101 | }, 102 | "node_modules/barbe": { 103 | "version": "3.0.16", 104 | "resolved": "https://registry.npmjs.org/barbe/-/barbe-3.0.16.tgz", 105 | "integrity": "sha512-WSJbowJ8dUfDUSWSZzJDD2BP+xwbLdGPbZMStzgUX8UDSS2stPLvi9pwCIsU9k8RXU6x56nIJzJYSfFct3C1+Q==", 106 | "dependencies": { 107 | "iterate-object": "^1.3.2", 108 | "regex-escape": "^3.0.0", 109 | "typpy": "^2.3.1" 110 | } 111 | }, 112 | "node_modules/bug-killer": { 113 | "version": "4.4.4", 114 | "resolved": "https://registry.npmjs.org/bug-killer/-/bug-killer-4.4.4.tgz", 115 | "integrity": "sha1-luAyK5Q3orBnLXiqzR7SvvEflFo=", 116 | "dependencies": { 117 | "ansi-parser": "^3.2.5", 118 | "couleurs": "^6.0.6", 119 | "daty": "^1.0.7", 120 | "deffy": "^2.2.2", 121 | "typpy": "^2.3.6" 122 | } 123 | }, 124 | "node_modules/byline": { 125 | "version": "4.2.2", 126 | "resolved": "https://registry.npmjs.org/byline/-/byline-4.2.2.tgz", 127 | "integrity": "sha1-wgOpilsCkIIqk4anjtosvVvNsy8=", 128 | "engines": { 129 | "node": ">=0.10.0" 130 | } 131 | }, 132 | "node_modules/camelo": { 133 | "version": "1.2.1", 134 | "resolved": "https://registry.npmjs.org/camelo/-/camelo-1.2.1.tgz", 135 | "integrity": "sha512-5O6lYuw6JR8viGfxFQhJTaO7cPTsnEaJUK2Gj0JeZ0O+iO78kxfeF47ocx6Ml0K8KWbE/JgBbgi3zF6lcUkvGw==", 136 | "dependencies": { 137 | "regex-escape": "^3.4.10", 138 | "uc-first-array": "^1.1.10" 139 | } 140 | }, 141 | "node_modules/class-methods": { 142 | "version": "1.0.12", 143 | "resolved": "https://registry.npmjs.org/class-methods/-/class-methods-1.0.12.tgz", 144 | "integrity": "sha512-14T82nNlU+OAhPNm4Fw4kJUS8klgt9n1+CdtB6LHvmWC5Wb89TZQ6CuCwEK2YR03O/hT0eHGIpQxtovAnN9CtA==", 145 | "dependencies": { 146 | "exclude-arr": "^1.0.0", 147 | "static-methods": "^1.0.0", 148 | "ul": "^5.2.1" 149 | } 150 | }, 151 | "node_modules/cli-box": { 152 | "version": "6.0.10", 153 | "resolved": "https://registry.npmjs.org/cli-box/-/cli-box-6.0.10.tgz", 154 | "integrity": "sha512-6jjSF6G1gOXaCyBQJKo3L3lZKxP8jzdECG7FBiA4m2w7K8jBxXXwsMb75fBLwoVwOtKwvgKjLJurw8HU5XNciw==", 155 | "dependencies": { 156 | "ansi-parser": "^3.2.1", 157 | "deffy": "^2.2.1", 158 | "is-undefined": "^1.0.0", 159 | "is-win": "^1.0.0", 160 | "ul": "^5.2.1" 161 | } 162 | }, 163 | "node_modules/cli-circle": { 164 | "version": "3.2.11", 165 | "resolved": "https://registry.npmjs.org/cli-circle/-/cli-circle-3.2.11.tgz", 166 | "integrity": "sha512-IU+ZgHR0Z9Ga+LqAeWefV9e5K7guBTXxxnzv9PYHA/t8LitBgGpZUYEJEINloiv3QlqbWnt5N5Dw+EyJSujR3g==", 167 | "dependencies": { 168 | "cli-graph": "^3.0.0", 169 | "typpy": "^2.3.3", 170 | "ul": "^5.0.0" 171 | } 172 | }, 173 | "node_modules/cli-gh-cal": { 174 | "version": "1.4.13", 175 | "resolved": "https://registry.npmjs.org/cli-gh-cal/-/cli-gh-cal-1.4.13.tgz", 176 | "integrity": "sha512-wNYMn0PM7XVcRaQ9DEI6ZRB9ZId8jpG9cprOo3QoV1KMm2WL3eSrPIXsqQxANsFeYQM4cgosJhqsTBKcDIZ6Vg==", 177 | "dependencies": { 178 | "ansi-parser": "^3.0.0", 179 | "bug-killer": "^4.2.5", 180 | "cli-box": "^6.0.5", 181 | "couleurs": "^6.0.5", 182 | "deffy": "^2.0.0", 183 | "git-stats-colors": "^2.3.8", 184 | "moment": "^2.9.0", 185 | "tilda": "^4.3.3", 186 | "typpy": "^2.0.0", 187 | "ul": "^5.0.0", 188 | "window-size": "^1.1.1" 189 | }, 190 | "bin": { 191 | "cli-gh-cal": "bin/cli-gh-cal" 192 | } 193 | }, 194 | "node_modules/cli-graph": { 195 | "version": "3.2.2", 196 | "resolved": "https://registry.npmjs.org/cli-graph/-/cli-graph-3.2.2.tgz", 197 | "integrity": "sha1-1oEKJjqxCXG+aIJ59n+smPjfdDo=", 198 | "dependencies": { 199 | "ul": "5.0.0" 200 | } 201 | }, 202 | "node_modules/cli-graph/node_modules/deffy": { 203 | "version": "2.0.0", 204 | "resolved": "https://registry.npmjs.org/deffy/-/deffy-2.0.0.tgz", 205 | "integrity": "sha1-+C4I7qUYxKCjCx8D7FBNJIryiTI=", 206 | "dependencies": { 207 | "typpy": "^2.0.0" 208 | } 209 | }, 210 | "node_modules/cli-graph/node_modules/typpy": { 211 | "version": "2.0.0", 212 | "resolved": "https://registry.npmjs.org/typpy/-/typpy-2.0.0.tgz", 213 | "integrity": "sha1-re87rMEv9Hr/kg+rA6j/MnnXN9Y=" 214 | }, 215 | "node_modules/cli-graph/node_modules/ul": { 216 | "version": "5.0.0", 217 | "resolved": "https://registry.npmjs.org/ul/-/ul-5.0.0.tgz", 218 | "integrity": "sha1-yoDXkwJfP9Xcm/g0aYGNMQp8mmI=", 219 | "dependencies": { 220 | "deffy": "2.0.0", 221 | "typpy": "2.0.0" 222 | } 223 | }, 224 | "node_modules/cli-pie": { 225 | "version": "2.4.2", 226 | "resolved": "https://registry.npmjs.org/cli-pie/-/cli-pie-2.4.2.tgz", 227 | "integrity": "sha512-/ixPjwAwH4wt2LHDN4IuOGyp+IdwASQXQTTLggaZWoCMr6ZAaRZItE7pCqKlgge3bj8TWF956Sli3g/Hmt5CVQ==", 228 | "dependencies": { 229 | "cli-circle": "^3.0.0", 230 | "couleurs": "^5.0.0", 231 | "flatcolors": "^3.0.0", 232 | "ul": "^5.0.0" 233 | } 234 | }, 235 | "node_modules/cli-pie/node_modules/couleurs": { 236 | "version": "5.2.1", 237 | "resolved": "https://registry.npmjs.org/couleurs/-/couleurs-5.2.1.tgz", 238 | "integrity": "sha1-U5n596FZhS7BQkT4Qb2FjwTcUqM=", 239 | "dependencies": { 240 | "flat-colors": "3.0.0", 241 | "typpy": "2.0.0", 242 | "x256": "0.0.2" 243 | } 244 | }, 245 | "node_modules/cli-pie/node_modules/typpy": { 246 | "version": "2.0.0", 247 | "resolved": "https://registry.npmjs.org/typpy/-/typpy-2.0.0.tgz", 248 | "integrity": "sha1-re87rMEv9Hr/kg+rA6j/MnnXN9Y=" 249 | }, 250 | "node_modules/clp": { 251 | "version": "4.0.12", 252 | "resolved": "https://registry.npmjs.org/clp/-/clp-4.0.12.tgz", 253 | "integrity": "sha512-DOQX14xsm4mM06JVzB/5nTk+tBdst+mFffz1OK4TWPa6++M/J7TJWuciXVwCRxTFzY2f+FRQARUu8+uqgQBpUQ==", 254 | "dependencies": { 255 | "is-number": "^2.1.0", 256 | "last-char": "^1.3.1", 257 | "match-it": "^1.0.0" 258 | } 259 | }, 260 | "node_modules/clp/node_modules/is-number": { 261 | "version": "2.1.0", 262 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", 263 | "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", 264 | "dependencies": { 265 | "kind-of": "^3.0.2" 266 | }, 267 | "engines": { 268 | "node": ">=0.10.0" 269 | } 270 | }, 271 | "node_modules/color-convert": { 272 | "version": "1.9.3", 273 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 274 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 275 | "dependencies": { 276 | "color-name": "1.1.3" 277 | } 278 | }, 279 | "node_modules/color-name": { 280 | "version": "1.1.3", 281 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 282 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" 283 | }, 284 | "node_modules/couleurs": { 285 | "version": "6.0.11", 286 | "resolved": "https://registry.npmjs.org/couleurs/-/couleurs-6.0.11.tgz", 287 | "integrity": "sha512-y5WUDtgQKw/tVViZCj3ACX8VseU0ONxiet8SRsE89uH4s/otRLXGOMymfVbKMFzedKOdxQpTcYWukRwkvgRYdw==", 288 | "dependencies": { 289 | "ansy": "^1.0.0", 290 | "color-convert": "^1.0.0", 291 | "iterate-object": "^1.3.1", 292 | "typpy": "^2.3.1" 293 | } 294 | }, 295 | "node_modules/custom-return": { 296 | "version": "1.0.12", 297 | "resolved": "https://registry.npmjs.org/custom-return/-/custom-return-1.0.12.tgz", 298 | "integrity": "sha512-Xy6IlEV6gW5Iu4YRoQe0A5RG1mzezawcTXzAk7u28oB2UilRfbbOc1C7RmWE6AJ1inSm8gghCkIpo0LUQfLbvw==", 299 | "dependencies": { 300 | "noop6": "^1.0.0" 301 | } 302 | }, 303 | "node_modules/date-unit-ms": { 304 | "version": "1.1.14", 305 | "resolved": "https://registry.npmjs.org/date-unit-ms/-/date-unit-ms-1.1.14.tgz", 306 | "integrity": "sha512-6vUHdMQkblV8lKYQqnTM2kUmWlFVG6F/0mzUbcnNygcR2vuUPeHAIE7BO7mj/brmgV1INSAG9D2GpgTLOEOHvg==" 307 | }, 308 | "node_modules/daty": { 309 | "version": "1.2.1", 310 | "resolved": "https://registry.npmjs.org/daty/-/daty-1.2.1.tgz", 311 | "integrity": "sha512-0ScX8eww2sJ1fnJuuLhP6JXonVrIIJZiVlGL6ve+Dnv3vPVFf3ZMDlose5+h/SnR4gQ1nmG3acoBP3Slycr4ag==", 312 | "dependencies": { 313 | "add-subtract-date": "^1.0.0", 314 | "class-methods": "^1.0.4", 315 | "date-unit-ms": "^1.1.0", 316 | "diff-dates": "^1.0.0", 317 | "formatoid": "^1.0.0" 318 | } 319 | }, 320 | "node_modules/days": { 321 | "version": "1.1.1", 322 | "resolved": "https://registry.npmjs.org/days/-/days-1.1.1.tgz", 323 | "integrity": "sha512-vzeIwVsEIyA35GH4+mPd4hjVDNI87wYANyZFs0BHjBr5kIBH5zEl7LfD6Wr4SFZca4D3CU9IH1w4DuZLlXzKRw==", 324 | "engines": { 325 | "node": ">=0.10.0" 326 | } 327 | }, 328 | "node_modules/debug-mode": { 329 | "version": "2.0.2", 330 | "resolved": "https://registry.npmjs.org/debug-mode/-/debug-mode-2.0.2.tgz", 331 | "integrity": "sha512-uOGKcpU0ZSADgNKzyoZ3I3Sj5xAgGGOavQKhH60sTrW4+EtOa2MDrcop+XUdRmLqI4p0rjSrqPcQbwlBtLLhRw==" 332 | }, 333 | "node_modules/deffy": { 334 | "version": "2.2.4", 335 | "resolved": "https://registry.npmjs.org/deffy/-/deffy-2.2.4.tgz", 336 | "integrity": "sha512-pLc9lsbsWjr6RxmJ2OLyvm+9l4j1yK69h+TML/gUit/t3vTijpkNGh8LioaJYTGO7F25m6HZndADcUOo2PsiUg==", 337 | "dependencies": { 338 | "typpy": "^2.0.0" 339 | } 340 | }, 341 | "node_modules/define-property": { 342 | "version": "1.0.0", 343 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", 344 | "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", 345 | "dependencies": { 346 | "is-descriptor": "^1.0.0" 347 | }, 348 | "engines": { 349 | "node": ">=0.10.0" 350 | } 351 | }, 352 | "node_modules/diff-dates": { 353 | "version": "1.0.14", 354 | "resolved": "https://registry.npmjs.org/diff-dates/-/diff-dates-1.0.14.tgz", 355 | "integrity": "sha512-JbWO1wl9jJZdLPLK/nENeUL68Mv7+SQQrXlEPSxuzZid89+FXpl7xSGxbPGd5z/2Xx3KJe4+fHPpaKnWnZ8V3w==", 356 | "dependencies": { 357 | "date-unit-ms": "^1.1.0" 358 | } 359 | }, 360 | "node_modules/err": { 361 | "version": "2.1.12", 362 | "resolved": "https://registry.npmjs.org/err/-/err-2.1.12.tgz", 363 | "integrity": "sha512-C0XHNJOnH072AC8q0L5oclAZvBCD8nzBb24bcHSqEkurDHyRo6bpOztgddHtH4Ik/9evmBCVW0nEY0NdnSt46Q==", 364 | "dependencies": { 365 | "barbe": "^3.0.4", 366 | "iterate-object": "^1.3.1", 367 | "typpy": "^2.2.0" 368 | } 369 | }, 370 | "node_modules/exclude-arr": { 371 | "version": "1.0.11", 372 | "resolved": "https://registry.npmjs.org/exclude-arr/-/exclude-arr-1.0.11.tgz", 373 | "integrity": "sha512-yQVFDXkkpDOhSPGOu2yG4fKmDsBiufj2M5uJRS6ijcLW7/pUvCxAHJ2YQTJUkLJ4nWbl+XZn/qwMzrWYfWFgFg==" 374 | }, 375 | "node_modules/exec-limiter": { 376 | "version": "3.2.13", 377 | "resolved": "https://registry.npmjs.org/exec-limiter/-/exec-limiter-3.2.13.tgz", 378 | "integrity": "sha512-86Ri699bwiHZVBzTzNj8gspqAhCPchg70zPVWIh3qzUOA1pUMcb272Em3LPk8AE0mS95B9yMJhtqF8vFJAn0dA==", 379 | "dependencies": { 380 | "limit-it": "^3.0.0", 381 | "typpy": "^2.1.0" 382 | } 383 | }, 384 | "node_modules/fillo": { 385 | "version": "1.0.13", 386 | "resolved": "https://registry.npmjs.org/fillo/-/fillo-1.0.13.tgz", 387 | "integrity": "sha512-9LYJ0ww96DUYETd2Bia5NS1b8rj42nEE5zsfcUwDErMopTs6BRBe4dRIVjrZGXSiK4vNSL/Q3u0dyqbmkA2Zdg==" 388 | }, 389 | "node_modules/flat-colors": { 390 | "version": "3.0.0", 391 | "resolved": "https://registry.npmjs.org/flat-colors/-/flat-colors-3.0.0.tgz", 392 | "integrity": "sha1-JTqxojmJwyHxOwrNS/c//0By7Lc=" 393 | }, 394 | "node_modules/flatcolors": { 395 | "version": "3.0.0", 396 | "resolved": "https://registry.npmjs.org/flatcolors/-/flatcolors-3.0.0.tgz", 397 | "integrity": "sha1-Q5MoO3M1qJsuTUcKqWb4zYofqz0=" 398 | }, 399 | "node_modules/formatoid": { 400 | "version": "1.2.4", 401 | "resolved": "https://registry.npmjs.org/formatoid/-/formatoid-1.2.4.tgz", 402 | "integrity": "sha512-9wWHOPJvbIheSpiHGl0xaBwdszlzPaeh2KqHVexGQnKpO85xrMoKvuf6M3q0B4uC3I9lkXjH6+8ipQC8PQ/7Gw==", 403 | "dependencies": { 404 | "days": "^1.0.1", 405 | "fillo": "^1.0.0", 406 | "months": "^1.0.0", 407 | "parse-it": "^1.0.0" 408 | } 409 | }, 410 | "node_modules/function.name": { 411 | "version": "1.0.13", 412 | "resolved": "https://registry.npmjs.org/function.name/-/function.name-1.0.13.tgz", 413 | "integrity": "sha512-mVrqdoy5npWZyoXl4DxCeuVF6delDcQjVS9aPdvLYlBxtMTZDR2B5GVEQEoM1jJyspCqg3C0v4ABkLE7tp9xFA==", 414 | "dependencies": { 415 | "noop6": "^1.0.1" 416 | } 417 | }, 418 | "node_modules/git-stats-colors": { 419 | "version": "2.3.13", 420 | "resolved": "https://registry.npmjs.org/git-stats-colors/-/git-stats-colors-2.3.13.tgz", 421 | "integrity": "sha512-PknbZgyly9nwNlK5V1K27dM714bxT8y0PPjhg2TGZnI7lBvsrfJkS7fVVVPgihsd5ceWatsaHw/cQn2ULbMhhg==", 422 | "dependencies": { 423 | "couleurs": "^6.0.5" 424 | } 425 | }, 426 | "node_modules/gitlog-parser": { 427 | "version": "0.0.4", 428 | "resolved": "https://registry.npmjs.org/gitlog-parser/-/gitlog-parser-0.0.4.tgz", 429 | "integrity": "sha1-YtuYR2UZv637TA05MbG/MB4I8fY=", 430 | "dependencies": { 431 | "byline": "^4.1.1" 432 | } 433 | }, 434 | "node_modules/gry": { 435 | "version": "6.1.0", 436 | "resolved": "https://registry.npmjs.org/gry/-/gry-6.1.0.tgz", 437 | "integrity": "sha512-zwTDU/VR4QSNa2NFnAPh0io88mdyGZypL11isQPf72LAOZ0JTNF8hNSV8xt1571DjcnKwiOhVNPwANtUoRZemA==", 438 | "dependencies": { 439 | "abs": "^1.2.1", 440 | "exec-limiter": "^3.0.0", 441 | "one-by-one": "^3.0.0", 442 | "ul": "^5.0.0" 443 | } 444 | }, 445 | "node_modules/has-flag": { 446 | "version": "1.0.0", 447 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", 448 | "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", 449 | "engines": { 450 | "node": ">=0.10.0" 451 | } 452 | }, 453 | "node_modules/indento": { 454 | "version": "1.1.13", 455 | "resolved": "https://registry.npmjs.org/indento/-/indento-1.1.13.tgz", 456 | "integrity": "sha512-YZWk3mreBEM7sBPddsiQnW9Z8SGg/gNpFfscJq00HCDS7pxcQWWWMSVKJU7YkTRyDu1Zv2s8zaK8gQWKmCXHlg==" 457 | }, 458 | "node_modules/is-accessor-descriptor": { 459 | "version": "1.0.0", 460 | "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", 461 | "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", 462 | "dependencies": { 463 | "kind-of": "^6.0.0" 464 | }, 465 | "engines": { 466 | "node": ">=0.10.0" 467 | } 468 | }, 469 | "node_modules/is-accessor-descriptor/node_modules/kind-of": { 470 | "version": "6.0.3", 471 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", 472 | "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", 473 | "engines": { 474 | "node": ">=0.10.0" 475 | } 476 | }, 477 | "node_modules/is-buffer": { 478 | "version": "1.1.6", 479 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", 480 | "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" 481 | }, 482 | "node_modules/is-data-descriptor": { 483 | "version": "1.0.0", 484 | "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", 485 | "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", 486 | "dependencies": { 487 | "kind-of": "^6.0.0" 488 | }, 489 | "engines": { 490 | "node": ">=0.10.0" 491 | } 492 | }, 493 | "node_modules/is-data-descriptor/node_modules/kind-of": { 494 | "version": "6.0.3", 495 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", 496 | "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", 497 | "engines": { 498 | "node": ">=0.10.0" 499 | } 500 | }, 501 | "node_modules/is-descriptor": { 502 | "version": "1.0.2", 503 | "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", 504 | "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", 505 | "dependencies": { 506 | "is-accessor-descriptor": "^1.0.0", 507 | "is-data-descriptor": "^1.0.0", 508 | "kind-of": "^6.0.2" 509 | }, 510 | "engines": { 511 | "node": ">=0.10.0" 512 | } 513 | }, 514 | "node_modules/is-descriptor/node_modules/kind-of": { 515 | "version": "6.0.3", 516 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", 517 | "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", 518 | "engines": { 519 | "node": ">=0.10.0" 520 | } 521 | }, 522 | "node_modules/is-empty-obj": { 523 | "version": "1.0.12", 524 | "resolved": "https://registry.npmjs.org/is-empty-obj/-/is-empty-obj-1.0.12.tgz", 525 | "integrity": "sha512-qHBAsU2hONx/K5o0VwTLRVfHb/cAsJY8+cYLLQBupCdKu0v5bxT83K9Dr997Go7gIoc4J6J0pD5qIIIvBFQZBQ==" 526 | }, 527 | "node_modules/is-there": { 528 | "version": "4.5.1", 529 | "resolved": "https://registry.npmjs.org/is-there/-/is-there-4.5.1.tgz", 530 | "integrity": "sha512-vIZ7HTXAoRoIwYSsTnxb0sg9L6rth+JOulNcavsbskQkCIWoSM2cjFOWZs4wGziGZER+Xgs/HXiCQZgiL8ppxQ==" 531 | }, 532 | "node_modules/is-undefined": { 533 | "version": "1.0.11", 534 | "resolved": "https://registry.npmjs.org/is-undefined/-/is-undefined-1.0.11.tgz", 535 | "integrity": "sha512-gRwyH8IRpV73MDlVefPllIjxBjrP9YAB0YCLtxnROhRkedTSzzBJgfxTC6HgP2/dttawQHWNZe88MvXS9Hbn/g==" 536 | }, 537 | "node_modules/is-win": { 538 | "version": "1.0.10", 539 | "resolved": "https://registry.npmjs.org/is-win/-/is-win-1.0.10.tgz", 540 | "integrity": "sha512-tJ9PPj5RW2RUaZ2lAIVRqQjMSynA44Ln89h+Ue+pOecoWIv6dLHvN6dtLxeCi/h5epPJPSVyuaNObLAMq62OEA==" 541 | }, 542 | "node_modules/iterate-object": { 543 | "version": "1.3.4", 544 | "resolved": "https://registry.npmjs.org/iterate-object/-/iterate-object-1.3.4.tgz", 545 | "integrity": "sha512-4dG1D1x/7g8PwHS9aK6QV5V94+ZvyP4+d19qDv43EzImmrndysIl4prmJ1hWWIGCqrZHyaHBm6BSEWHOLnpoNw==" 546 | }, 547 | "node_modules/kind-of": { 548 | "version": "3.2.2", 549 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 550 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 551 | "dependencies": { 552 | "is-buffer": "^1.1.5" 553 | }, 554 | "engines": { 555 | "node": ">=0.10.0" 556 | } 557 | }, 558 | "node_modules/last-char": { 559 | "version": "1.3.11", 560 | "resolved": "https://registry.npmjs.org/last-char/-/last-char-1.3.11.tgz", 561 | "integrity": "sha512-Thgr0MN085/Eo1UulZKOJy+HMoXSbw9CZ2iPqVxr6nFoIAUo6pkVc25wEU0A8cAz22wv2ZEPrlxhnguBmQ0CPA==" 562 | }, 563 | "node_modules/le-table": { 564 | "version": "6.1.10", 565 | "resolved": "https://registry.npmjs.org/le-table/-/le-table-6.1.10.tgz", 566 | "integrity": "sha512-ZpNb2ekquwQdsZUA/xwY6b/RzPpMbHdlOLnO7mimHuKOiNBSpRI+TXRIrBtUgS9t7crYKRrrJz6/7TVFen/ahg==", 567 | "dependencies": { 568 | "ansi-parser": "^3.2.1", 569 | "cli-box": "^6.0.0", 570 | "overlap": "^2.2.1", 571 | "ul": "^5.2.1" 572 | } 573 | }, 574 | "node_modules/limit-it": { 575 | "version": "3.2.10", 576 | "resolved": "https://registry.npmjs.org/limit-it/-/limit-it-3.2.10.tgz", 577 | "integrity": "sha512-T0NK99pHnkimldr1WUqvbGV1oWDku/xC9J/OqzJFsV1jeOS6Bwl8W7vkeQIBqwiON9dTALws+rX/XPMQqWerDQ==", 578 | "dependencies": { 579 | "typpy": "^2.0.0" 580 | } 581 | }, 582 | "node_modules/match-it": { 583 | "version": "1.0.9", 584 | "resolved": "https://registry.npmjs.org/match-it/-/match-it-1.0.9.tgz", 585 | "integrity": "sha512-l5qvhHYTFi86C+xBfxt/u0VaxVP6zP+E9RfGsxOK9no3fGNioCnntKvq400iys3tWTJd5JoR42DNpt8tEgrx7A==" 586 | }, 587 | "node_modules/moment": { 588 | "version": "2.29.4", 589 | "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", 590 | "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", 591 | "engines": { 592 | "node": "*" 593 | } 594 | }, 595 | "node_modules/months": { 596 | "version": "1.2.0", 597 | "resolved": "https://registry.npmjs.org/months/-/months-1.2.0.tgz", 598 | "integrity": "sha512-zFM7hUpziSYGk2DNObYGWgHdRRxAOgjl8CC1Rbl50p/q0rGDsREfk0nbxxmSIquVi/lEAuUY8nwbwkZ8biNCOQ==", 599 | "engines": { 600 | "node": ">=0.10.0" 601 | } 602 | }, 603 | "node_modules/noop6": { 604 | "version": "1.0.9", 605 | "resolved": "https://registry.npmjs.org/noop6/-/noop6-1.0.9.tgz", 606 | "integrity": "sha512-DB3Hwyd89dPr5HqEPg3YHjzvwh/mCqizC1zZ8vyofqc+TQRyPDnT4wgXXbLGF4z9YAzwwTLi8pNLhGqcbSjgkA==" 607 | }, 608 | "node_modules/obj-def": { 609 | "version": "1.0.9", 610 | "resolved": "https://registry.npmjs.org/obj-def/-/obj-def-1.0.9.tgz", 611 | "integrity": "sha512-bQ4ya3VYD6FAA1+s6mEhaURRHSmw4+sKaXE6UyXZ1XDYc5D+c7look25dFdydmLd18epUegh398gdDkMUZI9xg==", 612 | "dependencies": { 613 | "deffy": "^2.2.2" 614 | } 615 | }, 616 | "node_modules/one-by-one": { 617 | "version": "3.2.8", 618 | "resolved": "https://registry.npmjs.org/one-by-one/-/one-by-one-3.2.8.tgz", 619 | "integrity": "sha512-HR/pSzZdm46Xqj58K+Bu64kMbSTw8/u77AwWvV+rprO/OsuR++pPlkUJn+SmwqBGRgHKwSKQ974V3uls7crIeQ==", 620 | "dependencies": { 621 | "obj-def": "^1.0.0", 622 | "sliced": "^1.0.1" 623 | } 624 | }, 625 | "node_modules/overlap": { 626 | "version": "2.2.10", 627 | "resolved": "https://registry.npmjs.org/overlap/-/overlap-2.2.10.tgz", 628 | "integrity": "sha512-LtHwP1Xny/vEmLo+5sHFYUu9xbOIlOwmy6wsMWPojsYtjDLgjtfLbWV6HTwgEx6FKryK7gPW9S2EmUDI9wjBQQ==", 629 | "dependencies": { 630 | "ansi-parser": "3.0.0", 631 | "cli-box": "5.0.0", 632 | "couleurs": "5.0.0" 633 | } 634 | }, 635 | "node_modules/overlap/node_modules/ansi-parser": { 636 | "version": "3.0.0", 637 | "resolved": "https://registry.npmjs.org/ansi-parser/-/ansi-parser-3.0.0.tgz", 638 | "integrity": "sha1-lFwOcjLK9WdSFzdbPriJIAjBRik=" 639 | }, 640 | "node_modules/overlap/node_modules/cli-box": { 641 | "version": "5.0.0", 642 | "resolved": "https://registry.npmjs.org/cli-box/-/cli-box-5.0.0.tgz", 643 | "integrity": "sha1-hw6oqnfnwlF5QWzsz+XtBpCARgI=", 644 | "dependencies": { 645 | "ansi-parser": "3.0.0", 646 | "ul": "5.0.0" 647 | } 648 | }, 649 | "node_modules/overlap/node_modules/couleurs": { 650 | "version": "5.0.0", 651 | "resolved": "https://registry.npmjs.org/couleurs/-/couleurs-5.0.0.tgz", 652 | "integrity": "sha1-HNOs5cyhvsAEFXiydGSyZ2OH9ts=", 653 | "dependencies": { 654 | "flat-colors": "3.0.0", 655 | "typpy": "2.0.0", 656 | "x256": "0.0.2" 657 | } 658 | }, 659 | "node_modules/overlap/node_modules/deffy": { 660 | "version": "2.0.0", 661 | "resolved": "https://registry.npmjs.org/deffy/-/deffy-2.0.0.tgz", 662 | "integrity": "sha1-+C4I7qUYxKCjCx8D7FBNJIryiTI=", 663 | "dependencies": { 664 | "typpy": "^2.0.0" 665 | } 666 | }, 667 | "node_modules/overlap/node_modules/typpy": { 668 | "version": "2.0.0", 669 | "resolved": "https://registry.npmjs.org/typpy/-/typpy-2.0.0.tgz", 670 | "integrity": "sha1-re87rMEv9Hr/kg+rA6j/MnnXN9Y=" 671 | }, 672 | "node_modules/overlap/node_modules/ul": { 673 | "version": "5.0.0", 674 | "resolved": "https://registry.npmjs.org/ul/-/ul-5.0.0.tgz", 675 | "integrity": "sha1-yoDXkwJfP9Xcm/g0aYGNMQp8mmI=", 676 | "dependencies": { 677 | "deffy": "2.0.0", 678 | "typpy": "2.0.0" 679 | } 680 | }, 681 | "node_modules/parse-it": { 682 | "version": "1.0.10", 683 | "resolved": "https://registry.npmjs.org/parse-it/-/parse-it-1.0.10.tgz", 684 | "integrity": "sha512-VAG4EuoNd2TT2wSRUuKyLEkZR3MhdWc+3UPp5CDQzqSt/FiniG+yJ5RXyJYiuzVAMEKL4d97gx6O3LR5jEB3uQ==", 685 | "dependencies": { 686 | "regex-escape": "^3.4.0" 687 | } 688 | }, 689 | "node_modules/prompt-sync": { 690 | "version": "4.2.0", 691 | "resolved": "https://registry.npmjs.org/prompt-sync/-/prompt-sync-4.2.0.tgz", 692 | "integrity": "sha512-BuEzzc5zptP5LsgV5MZETjDaKSWfchl5U9Luiu8SKp7iZWD5tZalOxvNcZRwv+d2phNFr8xlbxmFNcRKfJOzJw==", 693 | "dependencies": { 694 | "strip-ansi": "^5.0.0" 695 | } 696 | }, 697 | "node_modules/prompt-sync/node_modules/strip-ansi": { 698 | "version": "5.2.0", 699 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", 700 | "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", 701 | "dependencies": { 702 | "ansi-regex": "^4.1.0" 703 | }, 704 | "engines": { 705 | "node": ">=6" 706 | } 707 | }, 708 | "node_modules/promptify": { 709 | "version": "2.0.1", 710 | "resolved": "https://registry.npmjs.org/promptify/-/promptify-2.0.1.tgz", 711 | "integrity": "sha512-+RHLo1+rfntA2Y76tiMo2uGTvS2afybMawR4PuJo24SUAqJCAMdaxDuo2uMsDNFJod09bVXYTAjpi+I+mGzoyA==", 712 | "dependencies": { 713 | "is-win": "^1.0.4", 714 | "ul": "^5.2.9" 715 | } 716 | }, 717 | "node_modules/r-json": { 718 | "version": "1.2.10", 719 | "resolved": "https://registry.npmjs.org/r-json/-/r-json-1.2.10.tgz", 720 | "integrity": "sha512-hu9vyLjSlHXT62NAS7DjI9WazDlvjN0lgp3n431dCVnirVcLkZIpzSwA3orhZEKzdDD2jqNYI+w0yG0aFf4kpA==" 721 | }, 722 | "node_modules/regex-escape": { 723 | "version": "3.4.10", 724 | "resolved": "https://registry.npmjs.org/regex-escape/-/regex-escape-3.4.10.tgz", 725 | "integrity": "sha512-qEqf7uzW+iYcKNLMDFnMkghhQBnGdivT6KqVQyKsyjSWnoFyooXVnxrw9dtv3AFLnD6VBGXxtZGAQNFGFTnCqA==" 726 | }, 727 | "node_modules/remove-blank-lines": { 728 | "version": "1.4.1", 729 | "resolved": "https://registry.npmjs.org/remove-blank-lines/-/remove-blank-lines-1.4.1.tgz", 730 | "integrity": "sha512-NEs3uvzpaZscL9qFGIHMO7iFy45/nRQC0bBeIMys8UDJT5CX/OcgDeRpcmwXGcr9Ez+IYZka7w0xhA9pEs7Cag==" 731 | }, 732 | "node_modules/sliced": { 733 | "version": "1.0.1", 734 | "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", 735 | "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=" 736 | }, 737 | "node_modules/static-methods": { 738 | "version": "1.0.12", 739 | "resolved": "https://registry.npmjs.org/static-methods/-/static-methods-1.0.12.tgz", 740 | "integrity": "sha512-QreySTr3LHtHk0OhrZ3RKvrV/4nBRyUPPCycmTUQTENIopEaDalZzI+q+KfmNmcxeHhA3WKe3h25lAxXZEDGVw==" 741 | }, 742 | "node_modules/supports-color": { 743 | "version": "3.2.3", 744 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", 745 | "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", 746 | "dependencies": { 747 | "has-flag": "^1.0.0" 748 | }, 749 | "engines": { 750 | "node": ">=0.8.0" 751 | } 752 | }, 753 | "node_modules/tilda": { 754 | "version": "4.4.16", 755 | "resolved": "https://registry.npmjs.org/tilda/-/tilda-4.4.16.tgz", 756 | "integrity": "sha512-5zDX3G4rQKPW/xug3odKzTPbeEq5jJW94PufTHWbObvXMo+e/ReMMX8eykUjYUIA+WSWl2tDb+30Kc1IS0VZLA==", 757 | "dependencies": { 758 | "ansi-parser": "^3.2.1", 759 | "arrs-to-obj": "^1.0.0", 760 | "auto-parse": "^1.2.0", 761 | "camelo": "^1.1.2", 762 | "clp": "^4.0.0", 763 | "debug-mode": "^2.0.0", 764 | "deffy": "^2.2.1", 765 | "err": "^2.1.0", 766 | "indento": "^1.1.1", 767 | "is-empty-obj": "^1.0.1", 768 | "is-undefined": "^1.0.0", 769 | "iterate-object": "^1.3.2", 770 | "le-table": "^6.1.0", 771 | "prompt-sync": "^4.1.4", 772 | "promptify": "^2.0.0", 773 | "r-json": "^1.2.1", 774 | "remove-blank-lines": "^1.0.1", 775 | "typpy": "^2.3.1", 776 | "ul": "^5.2.1", 777 | "wrap-text": "^1.0.0" 778 | } 779 | }, 780 | "node_modules/typpy": { 781 | "version": "2.3.13", 782 | "resolved": "https://registry.npmjs.org/typpy/-/typpy-2.3.13.tgz", 783 | "integrity": "sha512-vOxIcQz9sxHi+rT09SJ5aDgVgrPppQjwnnayTrMye1ODaU8gIZTDM19t9TxmEElbMihx2Nq/0/b/MtyKfayRqA==", 784 | "dependencies": { 785 | "function.name": "^1.0.3" 786 | } 787 | }, 788 | "node_modules/uc-first-array": { 789 | "version": "1.1.10", 790 | "resolved": "https://registry.npmjs.org/uc-first-array/-/uc-first-array-1.1.10.tgz", 791 | "integrity": "sha512-tX2PJLrqtexTxVN9hTTY+K5gPnF2gyj7SfjPF4Q2Xhbi1fSNiO12I/G+AoMzxJLwr9R50CmVn8iAhWCvZlJm3A==", 792 | "dependencies": { 793 | "ucfirst": "^1.0.0" 794 | } 795 | }, 796 | "node_modules/ucfirst": { 797 | "version": "1.0.0", 798 | "resolved": "https://registry.npmjs.org/ucfirst/-/ucfirst-1.0.0.tgz", 799 | "integrity": "sha1-ThBbZEjQXiZOzsQ14LkZNjxfLy8=" 800 | }, 801 | "node_modules/ul": { 802 | "version": "5.2.15", 803 | "resolved": "https://registry.npmjs.org/ul/-/ul-5.2.15.tgz", 804 | "integrity": "sha512-svLEUy8xSCip5IWnsRa0UOg+2zP0Wsj4qlbjTmX6GJSmvKMHADBuHOm1dpNkWqWPIGuVSqzUkV3Cris5JrlTRQ==", 805 | "dependencies": { 806 | "deffy": "^2.2.2", 807 | "typpy": "^2.3.4" 808 | } 809 | }, 810 | "node_modules/w-json": { 811 | "version": "1.3.10", 812 | "resolved": "https://registry.npmjs.org/w-json/-/w-json-1.3.10.tgz", 813 | "integrity": "sha512-XadVyw0xE+oZ5FGApXsdswv96rOhStzKqL53uSe5UaTadABGkWIg1+DTx8kiZ/VqTZTBneoL0l65RcPe4W3ecw==" 814 | }, 815 | "node_modules/window-size": { 816 | "version": "1.1.1", 817 | "resolved": "https://registry.npmjs.org/window-size/-/window-size-1.1.1.tgz", 818 | "integrity": "sha512-5D/9vujkmVQ7pSmc0SCBmHXbkv6eaHwXEx65MywhmUMsI8sGqJ972APq1lotfcwMKPFLuCFfL8xGHLIp7jaBmA==", 819 | "dependencies": { 820 | "define-property": "^1.0.0", 821 | "is-number": "^3.0.0" 822 | }, 823 | "bin": { 824 | "window-size": "cli.js" 825 | }, 826 | "engines": { 827 | "node": ">= 0.10.0" 828 | } 829 | }, 830 | "node_modules/window-size/node_modules/is-number": { 831 | "version": "3.0.0", 832 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", 833 | "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", 834 | "dependencies": { 835 | "kind-of": "^3.0.2" 836 | }, 837 | "engines": { 838 | "node": ">=0.10.0" 839 | } 840 | }, 841 | "node_modules/wrap-text": { 842 | "version": "1.0.9", 843 | "resolved": "https://registry.npmjs.org/wrap-text/-/wrap-text-1.0.9.tgz", 844 | "integrity": "sha512-NWfjspSgMDXQIMpKM56AwCQPI01OMFRYYJBh6dGNCfH7AOl+j/VqqbiopgJ4VuQfSluqLc+2ekqaPNpYAGZ/Vg==" 845 | }, 846 | "node_modules/x256": { 847 | "version": "0.0.2", 848 | "resolved": "https://registry.npmjs.org/x256/-/x256-0.0.2.tgz", 849 | "integrity": "sha1-ya8Yh296F1gB1WT+cK2egxd4STQ=", 850 | "engines": { 851 | "node": ">=0.4.0" 852 | } 853 | } 854 | }, 855 | "dependencies": { 856 | "abs": { 857 | "version": "1.3.14", 858 | "resolved": "https://registry.npmjs.org/abs/-/abs-1.3.14.tgz", 859 | "integrity": "sha512-PrS26IzwKLWwuURpiKl8wRmJ2KdR/azaVrLEBWG/TALwT20Y7qjtYp1qcMLHA4206hBHY5phv3w4pjf9NPv4Vw==", 860 | "requires": { 861 | "ul": "^5.0.0" 862 | } 863 | }, 864 | "add-subtract-date": { 865 | "version": "1.0.15", 866 | "resolved": "https://registry.npmjs.org/add-subtract-date/-/add-subtract-date-1.0.15.tgz", 867 | "integrity": "sha512-MiL4wnMyM999meyCrSA3LME9uZ/b5ptSd0ACDVUoTfutFwvkMyIN7nG7gjrU56WEk5RlFLBghabcgdYwY8s+nQ==" 868 | }, 869 | "ansi-parser": { 870 | "version": "3.2.10", 871 | "resolved": "https://registry.npmjs.org/ansi-parser/-/ansi-parser-3.2.10.tgz", 872 | "integrity": "sha512-CGKGIbd678lm15IXJXI1cTyOVAnMQw0jES+klW/yIc+GzYccsYanLMhczPIIj2hE64B79g75QfiuWrEWd6nJdg==" 873 | }, 874 | "ansi-regex": { 875 | "version": "4.1.1", 876 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", 877 | "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==" 878 | }, 879 | "ansi-styles": { 880 | "version": "3.2.1", 881 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 882 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 883 | "requires": { 884 | "color-convert": "^1.9.0" 885 | } 886 | }, 887 | "ansy": { 888 | "version": "1.0.15", 889 | "resolved": "https://registry.npmjs.org/ansy/-/ansy-1.0.15.tgz", 890 | "integrity": "sha512-mQyNSn58HN7aEthofkap0hn8jg7/5SJWrB0ypExgcECOwLppc0njH+QBA9X5VMiEN9SM0JlFZWJQGycxxInAqg==", 891 | "requires": { 892 | "ansi-styles": "^3.0.0", 893 | "custom-return": "^1.0.0", 894 | "supports-color": "^3.1.2", 895 | "ul": "^5.2.1" 896 | } 897 | }, 898 | "arrs-to-obj": { 899 | "version": "1.0.12", 900 | "resolved": "https://registry.npmjs.org/arrs-to-obj/-/arrs-to-obj-1.0.12.tgz", 901 | "integrity": "sha512-348sGggQcNrSVF4J009QXjfb5XrxwTw+tjMoOLIUrfRqxmSUf9W/U9hX3XdR5St/sX2Tc994WepBfRjr2BYg1g==" 902 | }, 903 | "auto-parse": { 904 | "version": "1.8.0", 905 | "resolved": "https://registry.npmjs.org/auto-parse/-/auto-parse-1.8.0.tgz", 906 | "integrity": "sha512-Uri4uC+K5cSi5hjM4snFrqPrjqUpwxeSW5EMTPvN7Ju3PlDzmXXDr5tjdzxPvvwgT3J7bmMDJ3Rm625nbrc72A==", 907 | "requires": { 908 | "typpy": "2.3.11" 909 | }, 910 | "dependencies": { 911 | "typpy": { 912 | "version": "2.3.11", 913 | "resolved": "https://registry.npmjs.org/typpy/-/typpy-2.3.11.tgz", 914 | "integrity": "sha512-Jh/fykZSaxeKO0ceMAs6agki9T5TNA9kiIR6fzKbvafKpIw8UlNlHhzuqKyi5lfJJ5VojJOx9tooIbyy7vHV/g==", 915 | "requires": { 916 | "function.name": "^1.0.3" 917 | } 918 | } 919 | } 920 | }, 921 | "barbe": { 922 | "version": "3.0.16", 923 | "resolved": "https://registry.npmjs.org/barbe/-/barbe-3.0.16.tgz", 924 | "integrity": "sha512-WSJbowJ8dUfDUSWSZzJDD2BP+xwbLdGPbZMStzgUX8UDSS2stPLvi9pwCIsU9k8RXU6x56nIJzJYSfFct3C1+Q==", 925 | "requires": { 926 | "iterate-object": "^1.3.2", 927 | "regex-escape": "^3.0.0", 928 | "typpy": "^2.3.1" 929 | } 930 | }, 931 | "bug-killer": { 932 | "version": "4.4.4", 933 | "resolved": "https://registry.npmjs.org/bug-killer/-/bug-killer-4.4.4.tgz", 934 | "integrity": "sha1-luAyK5Q3orBnLXiqzR7SvvEflFo=", 935 | "requires": { 936 | "ansi-parser": "^3.2.5", 937 | "couleurs": "^6.0.6", 938 | "daty": "^1.0.7", 939 | "deffy": "^2.2.2", 940 | "typpy": "^2.3.6" 941 | } 942 | }, 943 | "byline": { 944 | "version": "4.2.2", 945 | "resolved": "https://registry.npmjs.org/byline/-/byline-4.2.2.tgz", 946 | "integrity": "sha1-wgOpilsCkIIqk4anjtosvVvNsy8=" 947 | }, 948 | "camelo": { 949 | "version": "1.2.1", 950 | "resolved": "https://registry.npmjs.org/camelo/-/camelo-1.2.1.tgz", 951 | "integrity": "sha512-5O6lYuw6JR8viGfxFQhJTaO7cPTsnEaJUK2Gj0JeZ0O+iO78kxfeF47ocx6Ml0K8KWbE/JgBbgi3zF6lcUkvGw==", 952 | "requires": { 953 | "regex-escape": "^3.4.10", 954 | "uc-first-array": "^1.1.10" 955 | } 956 | }, 957 | "class-methods": { 958 | "version": "1.0.12", 959 | "resolved": "https://registry.npmjs.org/class-methods/-/class-methods-1.0.12.tgz", 960 | "integrity": "sha512-14T82nNlU+OAhPNm4Fw4kJUS8klgt9n1+CdtB6LHvmWC5Wb89TZQ6CuCwEK2YR03O/hT0eHGIpQxtovAnN9CtA==", 961 | "requires": { 962 | "exclude-arr": "^1.0.0", 963 | "static-methods": "^1.0.0", 964 | "ul": "^5.2.1" 965 | } 966 | }, 967 | "cli-box": { 968 | "version": "6.0.10", 969 | "resolved": "https://registry.npmjs.org/cli-box/-/cli-box-6.0.10.tgz", 970 | "integrity": "sha512-6jjSF6G1gOXaCyBQJKo3L3lZKxP8jzdECG7FBiA4m2w7K8jBxXXwsMb75fBLwoVwOtKwvgKjLJurw8HU5XNciw==", 971 | "requires": { 972 | "ansi-parser": "^3.2.1", 973 | "deffy": "^2.2.1", 974 | "is-undefined": "^1.0.0", 975 | "is-win": "^1.0.0", 976 | "ul": "^5.2.1" 977 | } 978 | }, 979 | "cli-circle": { 980 | "version": "3.2.11", 981 | "resolved": "https://registry.npmjs.org/cli-circle/-/cli-circle-3.2.11.tgz", 982 | "integrity": "sha512-IU+ZgHR0Z9Ga+LqAeWefV9e5K7guBTXxxnzv9PYHA/t8LitBgGpZUYEJEINloiv3QlqbWnt5N5Dw+EyJSujR3g==", 983 | "requires": { 984 | "cli-graph": "^3.0.0", 985 | "typpy": "^2.3.3", 986 | "ul": "^5.0.0" 987 | } 988 | }, 989 | "cli-gh-cal": { 990 | "version": "1.4.13", 991 | "resolved": "https://registry.npmjs.org/cli-gh-cal/-/cli-gh-cal-1.4.13.tgz", 992 | "integrity": "sha512-wNYMn0PM7XVcRaQ9DEI6ZRB9ZId8jpG9cprOo3QoV1KMm2WL3eSrPIXsqQxANsFeYQM4cgosJhqsTBKcDIZ6Vg==", 993 | "requires": { 994 | "ansi-parser": "^3.0.0", 995 | "bug-killer": "^4.2.5", 996 | "cli-box": "^6.0.5", 997 | "couleurs": "^6.0.5", 998 | "deffy": "^2.0.0", 999 | "git-stats-colors": "^2.3.8", 1000 | "moment": "^2.9.0", 1001 | "tilda": "^4.3.3", 1002 | "typpy": "^2.0.0", 1003 | "ul": "^5.0.0", 1004 | "window-size": "^1.1.1" 1005 | } 1006 | }, 1007 | "cli-graph": { 1008 | "version": "3.2.2", 1009 | "resolved": "https://registry.npmjs.org/cli-graph/-/cli-graph-3.2.2.tgz", 1010 | "integrity": "sha1-1oEKJjqxCXG+aIJ59n+smPjfdDo=", 1011 | "requires": { 1012 | "ul": "5.0.0" 1013 | }, 1014 | "dependencies": { 1015 | "deffy": { 1016 | "version": "2.0.0", 1017 | "resolved": "https://registry.npmjs.org/deffy/-/deffy-2.0.0.tgz", 1018 | "integrity": "sha1-+C4I7qUYxKCjCx8D7FBNJIryiTI=", 1019 | "requires": { 1020 | "typpy": "^2.0.0" 1021 | } 1022 | }, 1023 | "typpy": { 1024 | "version": "2.0.0", 1025 | "resolved": "https://registry.npmjs.org/typpy/-/typpy-2.0.0.tgz", 1026 | "integrity": "sha1-re87rMEv9Hr/kg+rA6j/MnnXN9Y=" 1027 | }, 1028 | "ul": { 1029 | "version": "5.0.0", 1030 | "resolved": "https://registry.npmjs.org/ul/-/ul-5.0.0.tgz", 1031 | "integrity": "sha1-yoDXkwJfP9Xcm/g0aYGNMQp8mmI=", 1032 | "requires": { 1033 | "deffy": "2.0.0", 1034 | "typpy": "2.0.0" 1035 | } 1036 | } 1037 | } 1038 | }, 1039 | "cli-pie": { 1040 | "version": "2.4.2", 1041 | "resolved": "https://registry.npmjs.org/cli-pie/-/cli-pie-2.4.2.tgz", 1042 | "integrity": "sha512-/ixPjwAwH4wt2LHDN4IuOGyp+IdwASQXQTTLggaZWoCMr6ZAaRZItE7pCqKlgge3bj8TWF956Sli3g/Hmt5CVQ==", 1043 | "requires": { 1044 | "cli-circle": "^3.0.0", 1045 | "couleurs": "^5.0.0", 1046 | "flatcolors": "^3.0.0", 1047 | "ul": "^5.0.0" 1048 | }, 1049 | "dependencies": { 1050 | "couleurs": { 1051 | "version": "5.2.1", 1052 | "resolved": "https://registry.npmjs.org/couleurs/-/couleurs-5.2.1.tgz", 1053 | "integrity": "sha1-U5n596FZhS7BQkT4Qb2FjwTcUqM=", 1054 | "requires": { 1055 | "flat-colors": "3.0.0", 1056 | "typpy": "2.0.0", 1057 | "x256": "0.0.2" 1058 | } 1059 | }, 1060 | "typpy": { 1061 | "version": "2.0.0", 1062 | "resolved": "https://registry.npmjs.org/typpy/-/typpy-2.0.0.tgz", 1063 | "integrity": "sha1-re87rMEv9Hr/kg+rA6j/MnnXN9Y=" 1064 | } 1065 | } 1066 | }, 1067 | "clp": { 1068 | "version": "4.0.12", 1069 | "resolved": "https://registry.npmjs.org/clp/-/clp-4.0.12.tgz", 1070 | "integrity": "sha512-DOQX14xsm4mM06JVzB/5nTk+tBdst+mFffz1OK4TWPa6++M/J7TJWuciXVwCRxTFzY2f+FRQARUu8+uqgQBpUQ==", 1071 | "requires": { 1072 | "is-number": "^2.1.0", 1073 | "last-char": "^1.3.1", 1074 | "match-it": "^1.0.0" 1075 | }, 1076 | "dependencies": { 1077 | "is-number": { 1078 | "version": "2.1.0", 1079 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", 1080 | "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", 1081 | "requires": { 1082 | "kind-of": "^3.0.2" 1083 | } 1084 | } 1085 | } 1086 | }, 1087 | "color-convert": { 1088 | "version": "1.9.3", 1089 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 1090 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 1091 | "requires": { 1092 | "color-name": "1.1.3" 1093 | } 1094 | }, 1095 | "color-name": { 1096 | "version": "1.1.3", 1097 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 1098 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" 1099 | }, 1100 | "couleurs": { 1101 | "version": "6.0.11", 1102 | "resolved": "https://registry.npmjs.org/couleurs/-/couleurs-6.0.11.tgz", 1103 | "integrity": "sha512-y5WUDtgQKw/tVViZCj3ACX8VseU0ONxiet8SRsE89uH4s/otRLXGOMymfVbKMFzedKOdxQpTcYWukRwkvgRYdw==", 1104 | "requires": { 1105 | "ansy": "^1.0.0", 1106 | "color-convert": "^1.0.0", 1107 | "iterate-object": "^1.3.1", 1108 | "typpy": "^2.3.1" 1109 | } 1110 | }, 1111 | "custom-return": { 1112 | "version": "1.0.12", 1113 | "resolved": "https://registry.npmjs.org/custom-return/-/custom-return-1.0.12.tgz", 1114 | "integrity": "sha512-Xy6IlEV6gW5Iu4YRoQe0A5RG1mzezawcTXzAk7u28oB2UilRfbbOc1C7RmWE6AJ1inSm8gghCkIpo0LUQfLbvw==", 1115 | "requires": { 1116 | "noop6": "^1.0.0" 1117 | } 1118 | }, 1119 | "date-unit-ms": { 1120 | "version": "1.1.14", 1121 | "resolved": "https://registry.npmjs.org/date-unit-ms/-/date-unit-ms-1.1.14.tgz", 1122 | "integrity": "sha512-6vUHdMQkblV8lKYQqnTM2kUmWlFVG6F/0mzUbcnNygcR2vuUPeHAIE7BO7mj/brmgV1INSAG9D2GpgTLOEOHvg==" 1123 | }, 1124 | "daty": { 1125 | "version": "1.2.1", 1126 | "resolved": "https://registry.npmjs.org/daty/-/daty-1.2.1.tgz", 1127 | "integrity": "sha512-0ScX8eww2sJ1fnJuuLhP6JXonVrIIJZiVlGL6ve+Dnv3vPVFf3ZMDlose5+h/SnR4gQ1nmG3acoBP3Slycr4ag==", 1128 | "requires": { 1129 | "add-subtract-date": "^1.0.0", 1130 | "class-methods": "^1.0.4", 1131 | "date-unit-ms": "^1.1.0", 1132 | "diff-dates": "^1.0.0", 1133 | "formatoid": "^1.0.0" 1134 | } 1135 | }, 1136 | "days": { 1137 | "version": "1.1.1", 1138 | "resolved": "https://registry.npmjs.org/days/-/days-1.1.1.tgz", 1139 | "integrity": "sha512-vzeIwVsEIyA35GH4+mPd4hjVDNI87wYANyZFs0BHjBr5kIBH5zEl7LfD6Wr4SFZca4D3CU9IH1w4DuZLlXzKRw==" 1140 | }, 1141 | "debug-mode": { 1142 | "version": "2.0.2", 1143 | "resolved": "https://registry.npmjs.org/debug-mode/-/debug-mode-2.0.2.tgz", 1144 | "integrity": "sha512-uOGKcpU0ZSADgNKzyoZ3I3Sj5xAgGGOavQKhH60sTrW4+EtOa2MDrcop+XUdRmLqI4p0rjSrqPcQbwlBtLLhRw==" 1145 | }, 1146 | "deffy": { 1147 | "version": "2.2.4", 1148 | "resolved": "https://registry.npmjs.org/deffy/-/deffy-2.2.4.tgz", 1149 | "integrity": "sha512-pLc9lsbsWjr6RxmJ2OLyvm+9l4j1yK69h+TML/gUit/t3vTijpkNGh8LioaJYTGO7F25m6HZndADcUOo2PsiUg==", 1150 | "requires": { 1151 | "typpy": "^2.0.0" 1152 | } 1153 | }, 1154 | "define-property": { 1155 | "version": "1.0.0", 1156 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", 1157 | "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", 1158 | "requires": { 1159 | "is-descriptor": "^1.0.0" 1160 | } 1161 | }, 1162 | "diff-dates": { 1163 | "version": "1.0.14", 1164 | "resolved": "https://registry.npmjs.org/diff-dates/-/diff-dates-1.0.14.tgz", 1165 | "integrity": "sha512-JbWO1wl9jJZdLPLK/nENeUL68Mv7+SQQrXlEPSxuzZid89+FXpl7xSGxbPGd5z/2Xx3KJe4+fHPpaKnWnZ8V3w==", 1166 | "requires": { 1167 | "date-unit-ms": "^1.1.0" 1168 | } 1169 | }, 1170 | "err": { 1171 | "version": "2.1.12", 1172 | "resolved": "https://registry.npmjs.org/err/-/err-2.1.12.tgz", 1173 | "integrity": "sha512-C0XHNJOnH072AC8q0L5oclAZvBCD8nzBb24bcHSqEkurDHyRo6bpOztgddHtH4Ik/9evmBCVW0nEY0NdnSt46Q==", 1174 | "requires": { 1175 | "barbe": "^3.0.4", 1176 | "iterate-object": "^1.3.1", 1177 | "typpy": "^2.2.0" 1178 | } 1179 | }, 1180 | "exclude-arr": { 1181 | "version": "1.0.11", 1182 | "resolved": "https://registry.npmjs.org/exclude-arr/-/exclude-arr-1.0.11.tgz", 1183 | "integrity": "sha512-yQVFDXkkpDOhSPGOu2yG4fKmDsBiufj2M5uJRS6ijcLW7/pUvCxAHJ2YQTJUkLJ4nWbl+XZn/qwMzrWYfWFgFg==" 1184 | }, 1185 | "exec-limiter": { 1186 | "version": "3.2.13", 1187 | "resolved": "https://registry.npmjs.org/exec-limiter/-/exec-limiter-3.2.13.tgz", 1188 | "integrity": "sha512-86Ri699bwiHZVBzTzNj8gspqAhCPchg70zPVWIh3qzUOA1pUMcb272Em3LPk8AE0mS95B9yMJhtqF8vFJAn0dA==", 1189 | "requires": { 1190 | "limit-it": "^3.0.0", 1191 | "typpy": "^2.1.0" 1192 | } 1193 | }, 1194 | "fillo": { 1195 | "version": "1.0.13", 1196 | "resolved": "https://registry.npmjs.org/fillo/-/fillo-1.0.13.tgz", 1197 | "integrity": "sha512-9LYJ0ww96DUYETd2Bia5NS1b8rj42nEE5zsfcUwDErMopTs6BRBe4dRIVjrZGXSiK4vNSL/Q3u0dyqbmkA2Zdg==" 1198 | }, 1199 | "flat-colors": { 1200 | "version": "3.0.0", 1201 | "resolved": "https://registry.npmjs.org/flat-colors/-/flat-colors-3.0.0.tgz", 1202 | "integrity": "sha1-JTqxojmJwyHxOwrNS/c//0By7Lc=" 1203 | }, 1204 | "flatcolors": { 1205 | "version": "3.0.0", 1206 | "resolved": "https://registry.npmjs.org/flatcolors/-/flatcolors-3.0.0.tgz", 1207 | "integrity": "sha1-Q5MoO3M1qJsuTUcKqWb4zYofqz0=" 1208 | }, 1209 | "formatoid": { 1210 | "version": "1.2.4", 1211 | "resolved": "https://registry.npmjs.org/formatoid/-/formatoid-1.2.4.tgz", 1212 | "integrity": "sha512-9wWHOPJvbIheSpiHGl0xaBwdszlzPaeh2KqHVexGQnKpO85xrMoKvuf6M3q0B4uC3I9lkXjH6+8ipQC8PQ/7Gw==", 1213 | "requires": { 1214 | "days": "^1.0.1", 1215 | "fillo": "^1.0.0", 1216 | "months": "^1.0.0", 1217 | "parse-it": "^1.0.0" 1218 | } 1219 | }, 1220 | "function.name": { 1221 | "version": "1.0.13", 1222 | "resolved": "https://registry.npmjs.org/function.name/-/function.name-1.0.13.tgz", 1223 | "integrity": "sha512-mVrqdoy5npWZyoXl4DxCeuVF6delDcQjVS9aPdvLYlBxtMTZDR2B5GVEQEoM1jJyspCqg3C0v4ABkLE7tp9xFA==", 1224 | "requires": { 1225 | "noop6": "^1.0.1" 1226 | } 1227 | }, 1228 | "git-stats-colors": { 1229 | "version": "2.3.13", 1230 | "resolved": "https://registry.npmjs.org/git-stats-colors/-/git-stats-colors-2.3.13.tgz", 1231 | "integrity": "sha512-PknbZgyly9nwNlK5V1K27dM714bxT8y0PPjhg2TGZnI7lBvsrfJkS7fVVVPgihsd5ceWatsaHw/cQn2ULbMhhg==", 1232 | "requires": { 1233 | "couleurs": "^6.0.5" 1234 | } 1235 | }, 1236 | "gitlog-parser": { 1237 | "version": "0.0.4", 1238 | "resolved": "https://registry.npmjs.org/gitlog-parser/-/gitlog-parser-0.0.4.tgz", 1239 | "integrity": "sha1-YtuYR2UZv637TA05MbG/MB4I8fY=", 1240 | "requires": { 1241 | "byline": "^4.1.1" 1242 | } 1243 | }, 1244 | "gry": { 1245 | "version": "6.1.0", 1246 | "resolved": "https://registry.npmjs.org/gry/-/gry-6.1.0.tgz", 1247 | "integrity": "sha512-zwTDU/VR4QSNa2NFnAPh0io88mdyGZypL11isQPf72LAOZ0JTNF8hNSV8xt1571DjcnKwiOhVNPwANtUoRZemA==", 1248 | "requires": { 1249 | "abs": "^1.2.1", 1250 | "exec-limiter": "^3.0.0", 1251 | "one-by-one": "^3.0.0", 1252 | "ul": "^5.0.0" 1253 | } 1254 | }, 1255 | "has-flag": { 1256 | "version": "1.0.0", 1257 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", 1258 | "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=" 1259 | }, 1260 | "indento": { 1261 | "version": "1.1.13", 1262 | "resolved": "https://registry.npmjs.org/indento/-/indento-1.1.13.tgz", 1263 | "integrity": "sha512-YZWk3mreBEM7sBPddsiQnW9Z8SGg/gNpFfscJq00HCDS7pxcQWWWMSVKJU7YkTRyDu1Zv2s8zaK8gQWKmCXHlg==" 1264 | }, 1265 | "is-accessor-descriptor": { 1266 | "version": "1.0.0", 1267 | "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", 1268 | "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", 1269 | "requires": { 1270 | "kind-of": "^6.0.0" 1271 | }, 1272 | "dependencies": { 1273 | "kind-of": { 1274 | "version": "6.0.3", 1275 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", 1276 | "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" 1277 | } 1278 | } 1279 | }, 1280 | "is-buffer": { 1281 | "version": "1.1.6", 1282 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", 1283 | "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" 1284 | }, 1285 | "is-data-descriptor": { 1286 | "version": "1.0.0", 1287 | "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", 1288 | "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", 1289 | "requires": { 1290 | "kind-of": "^6.0.0" 1291 | }, 1292 | "dependencies": { 1293 | "kind-of": { 1294 | "version": "6.0.3", 1295 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", 1296 | "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" 1297 | } 1298 | } 1299 | }, 1300 | "is-descriptor": { 1301 | "version": "1.0.2", 1302 | "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", 1303 | "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", 1304 | "requires": { 1305 | "is-accessor-descriptor": "^1.0.0", 1306 | "is-data-descriptor": "^1.0.0", 1307 | "kind-of": "^6.0.2" 1308 | }, 1309 | "dependencies": { 1310 | "kind-of": { 1311 | "version": "6.0.3", 1312 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", 1313 | "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" 1314 | } 1315 | } 1316 | }, 1317 | "is-empty-obj": { 1318 | "version": "1.0.12", 1319 | "resolved": "https://registry.npmjs.org/is-empty-obj/-/is-empty-obj-1.0.12.tgz", 1320 | "integrity": "sha512-qHBAsU2hONx/K5o0VwTLRVfHb/cAsJY8+cYLLQBupCdKu0v5bxT83K9Dr997Go7gIoc4J6J0pD5qIIIvBFQZBQ==" 1321 | }, 1322 | "is-there": { 1323 | "version": "4.5.1", 1324 | "resolved": "https://registry.npmjs.org/is-there/-/is-there-4.5.1.tgz", 1325 | "integrity": "sha512-vIZ7HTXAoRoIwYSsTnxb0sg9L6rth+JOulNcavsbskQkCIWoSM2cjFOWZs4wGziGZER+Xgs/HXiCQZgiL8ppxQ==" 1326 | }, 1327 | "is-undefined": { 1328 | "version": "1.0.11", 1329 | "resolved": "https://registry.npmjs.org/is-undefined/-/is-undefined-1.0.11.tgz", 1330 | "integrity": "sha512-gRwyH8IRpV73MDlVefPllIjxBjrP9YAB0YCLtxnROhRkedTSzzBJgfxTC6HgP2/dttawQHWNZe88MvXS9Hbn/g==" 1331 | }, 1332 | "is-win": { 1333 | "version": "1.0.10", 1334 | "resolved": "https://registry.npmjs.org/is-win/-/is-win-1.0.10.tgz", 1335 | "integrity": "sha512-tJ9PPj5RW2RUaZ2lAIVRqQjMSynA44Ln89h+Ue+pOecoWIv6dLHvN6dtLxeCi/h5epPJPSVyuaNObLAMq62OEA==" 1336 | }, 1337 | "iterate-object": { 1338 | "version": "1.3.4", 1339 | "resolved": "https://registry.npmjs.org/iterate-object/-/iterate-object-1.3.4.tgz", 1340 | "integrity": "sha512-4dG1D1x/7g8PwHS9aK6QV5V94+ZvyP4+d19qDv43EzImmrndysIl4prmJ1hWWIGCqrZHyaHBm6BSEWHOLnpoNw==" 1341 | }, 1342 | "kind-of": { 1343 | "version": "3.2.2", 1344 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 1345 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 1346 | "requires": { 1347 | "is-buffer": "^1.1.5" 1348 | } 1349 | }, 1350 | "last-char": { 1351 | "version": "1.3.11", 1352 | "resolved": "https://registry.npmjs.org/last-char/-/last-char-1.3.11.tgz", 1353 | "integrity": "sha512-Thgr0MN085/Eo1UulZKOJy+HMoXSbw9CZ2iPqVxr6nFoIAUo6pkVc25wEU0A8cAz22wv2ZEPrlxhnguBmQ0CPA==" 1354 | }, 1355 | "le-table": { 1356 | "version": "6.1.10", 1357 | "resolved": "https://registry.npmjs.org/le-table/-/le-table-6.1.10.tgz", 1358 | "integrity": "sha512-ZpNb2ekquwQdsZUA/xwY6b/RzPpMbHdlOLnO7mimHuKOiNBSpRI+TXRIrBtUgS9t7crYKRrrJz6/7TVFen/ahg==", 1359 | "requires": { 1360 | "ansi-parser": "^3.2.1", 1361 | "cli-box": "^6.0.0", 1362 | "overlap": "^2.2.1", 1363 | "ul": "^5.2.1" 1364 | } 1365 | }, 1366 | "limit-it": { 1367 | "version": "3.2.10", 1368 | "resolved": "https://registry.npmjs.org/limit-it/-/limit-it-3.2.10.tgz", 1369 | "integrity": "sha512-T0NK99pHnkimldr1WUqvbGV1oWDku/xC9J/OqzJFsV1jeOS6Bwl8W7vkeQIBqwiON9dTALws+rX/XPMQqWerDQ==", 1370 | "requires": { 1371 | "typpy": "^2.0.0" 1372 | } 1373 | }, 1374 | "match-it": { 1375 | "version": "1.0.9", 1376 | "resolved": "https://registry.npmjs.org/match-it/-/match-it-1.0.9.tgz", 1377 | "integrity": "sha512-l5qvhHYTFi86C+xBfxt/u0VaxVP6zP+E9RfGsxOK9no3fGNioCnntKvq400iys3tWTJd5JoR42DNpt8tEgrx7A==" 1378 | }, 1379 | "moment": { 1380 | "version": "2.29.4", 1381 | "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", 1382 | "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==" 1383 | }, 1384 | "months": { 1385 | "version": "1.2.0", 1386 | "resolved": "https://registry.npmjs.org/months/-/months-1.2.0.tgz", 1387 | "integrity": "sha512-zFM7hUpziSYGk2DNObYGWgHdRRxAOgjl8CC1Rbl50p/q0rGDsREfk0nbxxmSIquVi/lEAuUY8nwbwkZ8biNCOQ==" 1388 | }, 1389 | "noop6": { 1390 | "version": "1.0.9", 1391 | "resolved": "https://registry.npmjs.org/noop6/-/noop6-1.0.9.tgz", 1392 | "integrity": "sha512-DB3Hwyd89dPr5HqEPg3YHjzvwh/mCqizC1zZ8vyofqc+TQRyPDnT4wgXXbLGF4z9YAzwwTLi8pNLhGqcbSjgkA==" 1393 | }, 1394 | "obj-def": { 1395 | "version": "1.0.9", 1396 | "resolved": "https://registry.npmjs.org/obj-def/-/obj-def-1.0.9.tgz", 1397 | "integrity": "sha512-bQ4ya3VYD6FAA1+s6mEhaURRHSmw4+sKaXE6UyXZ1XDYc5D+c7look25dFdydmLd18epUegh398gdDkMUZI9xg==", 1398 | "requires": { 1399 | "deffy": "^2.2.2" 1400 | } 1401 | }, 1402 | "one-by-one": { 1403 | "version": "3.2.8", 1404 | "resolved": "https://registry.npmjs.org/one-by-one/-/one-by-one-3.2.8.tgz", 1405 | "integrity": "sha512-HR/pSzZdm46Xqj58K+Bu64kMbSTw8/u77AwWvV+rprO/OsuR++pPlkUJn+SmwqBGRgHKwSKQ974V3uls7crIeQ==", 1406 | "requires": { 1407 | "obj-def": "^1.0.0", 1408 | "sliced": "^1.0.1" 1409 | } 1410 | }, 1411 | "overlap": { 1412 | "version": "2.2.10", 1413 | "resolved": "https://registry.npmjs.org/overlap/-/overlap-2.2.10.tgz", 1414 | "integrity": "sha512-LtHwP1Xny/vEmLo+5sHFYUu9xbOIlOwmy6wsMWPojsYtjDLgjtfLbWV6HTwgEx6FKryK7gPW9S2EmUDI9wjBQQ==", 1415 | "requires": { 1416 | "ansi-parser": "3.0.0", 1417 | "cli-box": "5.0.0", 1418 | "couleurs": "5.0.0" 1419 | }, 1420 | "dependencies": { 1421 | "ansi-parser": { 1422 | "version": "3.0.0", 1423 | "resolved": "https://registry.npmjs.org/ansi-parser/-/ansi-parser-3.0.0.tgz", 1424 | "integrity": "sha1-lFwOcjLK9WdSFzdbPriJIAjBRik=" 1425 | }, 1426 | "cli-box": { 1427 | "version": "5.0.0", 1428 | "resolved": "https://registry.npmjs.org/cli-box/-/cli-box-5.0.0.tgz", 1429 | "integrity": "sha1-hw6oqnfnwlF5QWzsz+XtBpCARgI=", 1430 | "requires": { 1431 | "ansi-parser": "3.0.0", 1432 | "ul": "5.0.0" 1433 | } 1434 | }, 1435 | "couleurs": { 1436 | "version": "5.0.0", 1437 | "resolved": "https://registry.npmjs.org/couleurs/-/couleurs-5.0.0.tgz", 1438 | "integrity": "sha1-HNOs5cyhvsAEFXiydGSyZ2OH9ts=", 1439 | "requires": { 1440 | "flat-colors": "3.0.0", 1441 | "typpy": "2.0.0", 1442 | "x256": "0.0.2" 1443 | } 1444 | }, 1445 | "deffy": { 1446 | "version": "2.0.0", 1447 | "resolved": "https://registry.npmjs.org/deffy/-/deffy-2.0.0.tgz", 1448 | "integrity": "sha1-+C4I7qUYxKCjCx8D7FBNJIryiTI=", 1449 | "requires": { 1450 | "typpy": "^2.0.0" 1451 | } 1452 | }, 1453 | "typpy": { 1454 | "version": "2.0.0", 1455 | "resolved": "https://registry.npmjs.org/typpy/-/typpy-2.0.0.tgz", 1456 | "integrity": "sha1-re87rMEv9Hr/kg+rA6j/MnnXN9Y=" 1457 | }, 1458 | "ul": { 1459 | "version": "5.0.0", 1460 | "resolved": "https://registry.npmjs.org/ul/-/ul-5.0.0.tgz", 1461 | "integrity": "sha1-yoDXkwJfP9Xcm/g0aYGNMQp8mmI=", 1462 | "requires": { 1463 | "deffy": "2.0.0", 1464 | "typpy": "2.0.0" 1465 | } 1466 | } 1467 | } 1468 | }, 1469 | "parse-it": { 1470 | "version": "1.0.10", 1471 | "resolved": "https://registry.npmjs.org/parse-it/-/parse-it-1.0.10.tgz", 1472 | "integrity": "sha512-VAG4EuoNd2TT2wSRUuKyLEkZR3MhdWc+3UPp5CDQzqSt/FiniG+yJ5RXyJYiuzVAMEKL4d97gx6O3LR5jEB3uQ==", 1473 | "requires": { 1474 | "regex-escape": "^3.4.0" 1475 | } 1476 | }, 1477 | "prompt-sync": { 1478 | "version": "4.2.0", 1479 | "resolved": "https://registry.npmjs.org/prompt-sync/-/prompt-sync-4.2.0.tgz", 1480 | "integrity": "sha512-BuEzzc5zptP5LsgV5MZETjDaKSWfchl5U9Luiu8SKp7iZWD5tZalOxvNcZRwv+d2phNFr8xlbxmFNcRKfJOzJw==", 1481 | "requires": { 1482 | "strip-ansi": "^5.0.0" 1483 | }, 1484 | "dependencies": { 1485 | "strip-ansi": { 1486 | "version": "5.2.0", 1487 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", 1488 | "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", 1489 | "requires": { 1490 | "ansi-regex": "^4.1.0" 1491 | } 1492 | } 1493 | } 1494 | }, 1495 | "promptify": { 1496 | "version": "2.0.1", 1497 | "resolved": "https://registry.npmjs.org/promptify/-/promptify-2.0.1.tgz", 1498 | "integrity": "sha512-+RHLo1+rfntA2Y76tiMo2uGTvS2afybMawR4PuJo24SUAqJCAMdaxDuo2uMsDNFJod09bVXYTAjpi+I+mGzoyA==", 1499 | "requires": { 1500 | "is-win": "^1.0.4", 1501 | "ul": "^5.2.9" 1502 | } 1503 | }, 1504 | "r-json": { 1505 | "version": "1.2.10", 1506 | "resolved": "https://registry.npmjs.org/r-json/-/r-json-1.2.10.tgz", 1507 | "integrity": "sha512-hu9vyLjSlHXT62NAS7DjI9WazDlvjN0lgp3n431dCVnirVcLkZIpzSwA3orhZEKzdDD2jqNYI+w0yG0aFf4kpA==" 1508 | }, 1509 | "regex-escape": { 1510 | "version": "3.4.10", 1511 | "resolved": "https://registry.npmjs.org/regex-escape/-/regex-escape-3.4.10.tgz", 1512 | "integrity": "sha512-qEqf7uzW+iYcKNLMDFnMkghhQBnGdivT6KqVQyKsyjSWnoFyooXVnxrw9dtv3AFLnD6VBGXxtZGAQNFGFTnCqA==" 1513 | }, 1514 | "remove-blank-lines": { 1515 | "version": "1.4.1", 1516 | "resolved": "https://registry.npmjs.org/remove-blank-lines/-/remove-blank-lines-1.4.1.tgz", 1517 | "integrity": "sha512-NEs3uvzpaZscL9qFGIHMO7iFy45/nRQC0bBeIMys8UDJT5CX/OcgDeRpcmwXGcr9Ez+IYZka7w0xhA9pEs7Cag==" 1518 | }, 1519 | "sliced": { 1520 | "version": "1.0.1", 1521 | "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", 1522 | "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=" 1523 | }, 1524 | "static-methods": { 1525 | "version": "1.0.12", 1526 | "resolved": "https://registry.npmjs.org/static-methods/-/static-methods-1.0.12.tgz", 1527 | "integrity": "sha512-QreySTr3LHtHk0OhrZ3RKvrV/4nBRyUPPCycmTUQTENIopEaDalZzI+q+KfmNmcxeHhA3WKe3h25lAxXZEDGVw==" 1528 | }, 1529 | "supports-color": { 1530 | "version": "3.2.3", 1531 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", 1532 | "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", 1533 | "requires": { 1534 | "has-flag": "^1.0.0" 1535 | } 1536 | }, 1537 | "tilda": { 1538 | "version": "4.4.16", 1539 | "resolved": "https://registry.npmjs.org/tilda/-/tilda-4.4.16.tgz", 1540 | "integrity": "sha512-5zDX3G4rQKPW/xug3odKzTPbeEq5jJW94PufTHWbObvXMo+e/ReMMX8eykUjYUIA+WSWl2tDb+30Kc1IS0VZLA==", 1541 | "requires": { 1542 | "ansi-parser": "^3.2.1", 1543 | "arrs-to-obj": "^1.0.0", 1544 | "auto-parse": "^1.2.0", 1545 | "camelo": "^1.1.2", 1546 | "clp": "^4.0.0", 1547 | "debug-mode": "^2.0.0", 1548 | "deffy": "^2.2.1", 1549 | "err": "^2.1.0", 1550 | "indento": "^1.1.1", 1551 | "is-empty-obj": "^1.0.1", 1552 | "is-undefined": "^1.0.0", 1553 | "iterate-object": "^1.3.2", 1554 | "le-table": "^6.1.0", 1555 | "prompt-sync": "^4.1.4", 1556 | "promptify": "^2.0.0", 1557 | "r-json": "^1.2.1", 1558 | "remove-blank-lines": "^1.0.1", 1559 | "typpy": "^2.3.1", 1560 | "ul": "^5.2.1", 1561 | "wrap-text": "^1.0.0" 1562 | } 1563 | }, 1564 | "typpy": { 1565 | "version": "2.3.13", 1566 | "resolved": "https://registry.npmjs.org/typpy/-/typpy-2.3.13.tgz", 1567 | "integrity": "sha512-vOxIcQz9sxHi+rT09SJ5aDgVgrPppQjwnnayTrMye1ODaU8gIZTDM19t9TxmEElbMihx2Nq/0/b/MtyKfayRqA==", 1568 | "requires": { 1569 | "function.name": "^1.0.3" 1570 | } 1571 | }, 1572 | "uc-first-array": { 1573 | "version": "1.1.10", 1574 | "resolved": "https://registry.npmjs.org/uc-first-array/-/uc-first-array-1.1.10.tgz", 1575 | "integrity": "sha512-tX2PJLrqtexTxVN9hTTY+K5gPnF2gyj7SfjPF4Q2Xhbi1fSNiO12I/G+AoMzxJLwr9R50CmVn8iAhWCvZlJm3A==", 1576 | "requires": { 1577 | "ucfirst": "^1.0.0" 1578 | } 1579 | }, 1580 | "ucfirst": { 1581 | "version": "1.0.0", 1582 | "resolved": "https://registry.npmjs.org/ucfirst/-/ucfirst-1.0.0.tgz", 1583 | "integrity": "sha1-ThBbZEjQXiZOzsQ14LkZNjxfLy8=" 1584 | }, 1585 | "ul": { 1586 | "version": "5.2.15", 1587 | "resolved": "https://registry.npmjs.org/ul/-/ul-5.2.15.tgz", 1588 | "integrity": "sha512-svLEUy8xSCip5IWnsRa0UOg+2zP0Wsj4qlbjTmX6GJSmvKMHADBuHOm1dpNkWqWPIGuVSqzUkV3Cris5JrlTRQ==", 1589 | "requires": { 1590 | "deffy": "^2.2.2", 1591 | "typpy": "^2.3.4" 1592 | } 1593 | }, 1594 | "w-json": { 1595 | "version": "1.3.10", 1596 | "resolved": "https://registry.npmjs.org/w-json/-/w-json-1.3.10.tgz", 1597 | "integrity": "sha512-XadVyw0xE+oZ5FGApXsdswv96rOhStzKqL53uSe5UaTadABGkWIg1+DTx8kiZ/VqTZTBneoL0l65RcPe4W3ecw==" 1598 | }, 1599 | "window-size": { 1600 | "version": "1.1.1", 1601 | "resolved": "https://registry.npmjs.org/window-size/-/window-size-1.1.1.tgz", 1602 | "integrity": "sha512-5D/9vujkmVQ7pSmc0SCBmHXbkv6eaHwXEx65MywhmUMsI8sGqJ972APq1lotfcwMKPFLuCFfL8xGHLIp7jaBmA==", 1603 | "requires": { 1604 | "define-property": "^1.0.0", 1605 | "is-number": "^3.0.0" 1606 | }, 1607 | "dependencies": { 1608 | "is-number": { 1609 | "version": "3.0.0", 1610 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", 1611 | "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", 1612 | "requires": { 1613 | "kind-of": "^3.0.2" 1614 | } 1615 | } 1616 | } 1617 | }, 1618 | "wrap-text": { 1619 | "version": "1.0.9", 1620 | "resolved": "https://registry.npmjs.org/wrap-text/-/wrap-text-1.0.9.tgz", 1621 | "integrity": "sha512-NWfjspSgMDXQIMpKM56AwCQPI01OMFRYYJBh6dGNCfH7AOl+j/VqqbiopgJ4VuQfSluqLc+2ekqaPNpYAGZ/Vg==" 1622 | }, 1623 | "x256": { 1624 | "version": "0.0.2", 1625 | "resolved": "https://registry.npmjs.org/x256/-/x256-0.0.2.tgz", 1626 | "integrity": "sha1-ya8Yh296F1gB1WT+cK2egxd4STQ=" 1627 | } 1628 | } 1629 | } 1630 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "bin": { 3 | "git-stats": "bin/git-stats" 4 | }, 5 | "name": "git-stats", 6 | "version": "3.2.1", 7 | "description": "Local git statistics including GitHub-like contributions calendars.", 8 | "main": "lib/index.js", 9 | "scripts": { 10 | "test": "node test", 11 | "postinstall": "node scripts/migration/2.0.0.js" 12 | }, 13 | "author": "Ionică Bizău (https://ionicabizau.net)", 14 | "contributors": [ 15 | "Gnab ", 16 | "William Boman ", 17 | "Fabian Furger ", 18 | "Jonah Lawrence " 19 | ], 20 | "license": "MIT", 21 | "repository": { 22 | "type": "git", 23 | "url": "https://github.com/IonicaBizau/git-stats.git" 24 | }, 25 | "keywords": [ 26 | "git", 27 | "stats", 28 | "github", 29 | "cli" 30 | ], 31 | "bugs": { 32 | "url": "https://github.com/IonicaBizau/git-stats/issues" 33 | }, 34 | "homepage": "https://github.com/IonicaBizau/git-stats", 35 | "dependencies": { 36 | "abs": "^1.0.0", 37 | "bug-killer": "^4.0.0", 38 | "cli-gh-cal": "^1.4.0", 39 | "cli-pie": "^2.0.0", 40 | "deffy": "^2.2.2", 41 | "gitlog-parser": "0.0.4", 42 | "gry": "^6.1.0", 43 | "is-there": "^4.0.0", 44 | "iterate-object": "^1.1.0", 45 | "moment": "^2.29.3", 46 | "r-json": "^1.0.0", 47 | "tilda": "^4.3.3", 48 | "typpy": "^2.1.0", 49 | "ul": "^5.0.0", 50 | "w-json": "^1.0.0" 51 | }, 52 | "blah": { 53 | "h_img": "http://i.imgur.com/Q7TQYHx.png", 54 | "description": [ 55 | { 56 | "p": "I'd be curious to see your calendar with all your commits. Ping me on Twitter ([**@IonicaBizau**](https://twitter.com/IonicaBizau)). :smile: Until then, here's my calendar:" 57 | }, 58 | { 59 | "img": { 60 | "source": "http://i.imgur.com/PpM0i3v.png" 61 | } 62 | }, 63 | { 64 | "h2": "Contents" 65 | }, 66 | { 67 | "ul": [ 68 | "[Installation](#cloud-installation)", 69 | [ 70 | "[Usage](#usage)", 71 | { 72 | "ul": [ 73 | "[Importing and deleting commits](#importing-and-deleting-commits)", 74 | "[Importing all the commits from GitHub and BitBucket](#importing-all-the-commits-from-github-and-bitbucket)", 75 | "[What about the GitHub Contributions calendar?](#what-about-the-github-contributions-calendar)" 76 | ] 77 | } 78 | ], 79 | "[Documentation](#memo-documentation)", 80 | "[How to contribute](#yum-how-to-contribute)" 81 | ] 82 | } 83 | ], 84 | "installation_command": { 85 | "language": "sh", 86 | "content": [ 87 | "# Install the package globally", 88 | "npm i -g git-stats", 89 | "", 90 | "# Initialize git hooks", 91 | "# This is for tracking the new commits", 92 | "curl -s https://raw.githubusercontent.com/IonicaBizau/git-stats/master/scripts/init-git-post-commit | bash" 93 | ] 94 | }, 95 | "installation": [ 96 | { 97 | "h2": "Usage" 98 | }, 99 | { 100 | "h3": "Importing and deleting commits" 101 | }, 102 | { 103 | "p": [ 104 | "I know it's not nice to start your git commit calendar from scratch. That's why I created [`git-stats-importer`](https://github.com/IonicaBizau/git-stats-importer)–a tool which imports or deletes the commits from selected repositories.", 105 | "Check it out here: https://github.com/IonicaBizau/git-stats-importer", 106 | "The usage is simple:" 107 | ] 108 | }, 109 | { 110 | "code": { 111 | "language": "sh", 112 | "content": [ 113 | "# Install the importer tool", 114 | "$ npm install -g git-stats-importer", 115 | "", 116 | "# Go to the repository you want to import", 117 | "$ cd path/to/my-repository", 118 | "", 119 | "# Import the commits", 120 | "$ git-stats-importer", 121 | "", 122 | "# ...or delete them if that's a dummy repository", 123 | "$ git-stats-importer --delete" 124 | ] 125 | } 126 | }, 127 | { 128 | "h3": "Importing all the commits from GitHub and BitBucket" 129 | }, 130 | { 131 | "p": "Yes, that's also possible. I [built a tool which downloads and then imports all the commits you have pushed to GitHub and BitBucket](https://github.com/IonicaBizau/repository-downloader)!" 132 | }, 133 | { 134 | "code": { 135 | "language": "sh", 136 | "content": [ 137 | "# Download the repository downloader", 138 | "$ git clone https://github.com/IonicaBizau/repository-downloader.git", 139 | "", 140 | "# Go to repository downloader", 141 | "$ cd repository-downloader", 142 | "", 143 | "# Install the dependencies", 144 | "$ npm install", 145 | "", 146 | "# Start downloading and importing", 147 | "$ ./start" 148 | ] 149 | } 150 | }, 151 | { 152 | "h3": "What about the GitHub Contributions calendar?" 153 | }, 154 | { 155 | "p": "If you want to visualize the calendars that appear on GitHub profiles, you can do that using [`ghcal`](https://github.com/IonicaBizau/ghcal)." 156 | }, 157 | { 158 | "code": { 159 | "language": "sh", 160 | "content": [ 161 | "# Install ghcal", 162 | "$ npm install -g ghcal", 163 | "", 164 | "# Check out @alysonla's contributions", 165 | "$ ghcal -u alysonla" 166 | ] 167 | } 168 | }, 169 | { 170 | "p": [ 171 | "For more detailed documentation, check out the repository: https://github.com/IonicaBizau/ghcal.", 172 | "If want to get even more GitHub stats in your terminal, you may want to try [`github-stats`](https://github.com/IonicaBizau/github-stats)--this is like `git-stats` but with data taken from GitHub." 173 | ] 174 | }, 175 | { 176 | "h2": "Using the configuration file" 177 | }, 178 | { 179 | "p": [ 180 | "You can tweak the git-stats behavior using a configuration file in your home directory: `~/.git-stats-config.js`.", 181 | "This file should export an object, like below (defaults are listed):" 182 | ] 183 | }, 184 | { 185 | "code": { 186 | "language": "js", 187 | "content": [ 188 | "module.exports = {", 189 | " // \"DARK\", \"LIGHT\" or an object interpreted by IonicaBizau/node-git-stats-colors", 190 | " \"theme\": \"DARK\"", 191 | "", 192 | " // The file where the commit hashes will be stored", 193 | " , \"path\": \"~/.git-stats\"", 194 | "", 195 | " // [DEPRECATED] First day of the week https://github.com/IonicaBizau/git-stats/issues/121", 196 | " , first_day: \"Sun\"", 197 | "", 198 | " // This defaults to *one year ago*", 199 | " // It can be any parsable date", 200 | " , since: undefined", 201 | "", 202 | " // This defaults to *now*", 203 | " // It can be any parsable date", 204 | " , until: undefined", 205 | "", 206 | " // Don't show authors by default", 207 | " // If true, this will enable the authors pie", 208 | " , authors: false", 209 | "", 210 | " // No global activity by default", 211 | " // If true, this will enable the global activity calendar in the current project", 212 | " , global_activity: false", 213 | "};" 214 | ] 215 | } 216 | }, 217 | { 218 | "p": "Since it's a js file, you can `require` any other modules there." 219 | }, 220 | { 221 | "h2": "Saving the data as HTML and images" 222 | }, 223 | { 224 | "p": [ 225 | "`git-stats --raw` outputs raw JSON format which can be consumed by other tools to generate results such as HTML files or images.", 226 | "[`git-stats-html`](https://github.com/IonicaBizau/git-stats-html) interprets the JSON data and generates an HTML file. Example:", 227 | { 228 | "code": { 229 | "content": [ 230 | "# Install git-stats-html", 231 | "npm install -g git-stats-html", 232 | "", 233 | "# Export the data from the last year (generate out.html)", 234 | "git-stats --raw | git-stats-html -o out.html", 235 | "", 236 | "# Export data since 2015 (save the results in out.html)", 237 | "git-stats --since '1 January 2015' --raw | ./bin/git-stats-html -o out.html --big" 238 | ], 239 | "language": "sh" 240 | } 241 | }, 242 | "After we have the HTML file, we can generate an image file using [`pageres`](https://github.com/sindresorhus/pageres) by [**@sindresorhus**](https://github.com/sindresorhus/):", 243 | { 244 | "code": { 245 | "content": [ 246 | "# Install pageres", 247 | "npm install -g pageres-cli", 248 | "", 249 | "# Generate the image from HTML", 250 | "pageres out.html 775x250" 251 | ], 252 | "language": "sh" 253 | } 254 | } 255 | ] 256 | }, 257 | { 258 | "h2": "Cross-platform compatibility" 259 | }, 260 | { 261 | "p": [ 262 | "`git-stats` is working fine in terminal emulators supporting ANSI styles. It should work fine on Linux and OS X.", 263 | "If you run `git-stats` to display graph on Windows, please use a terminal that can properly display ANSI colors.", 264 | "Cygwin Terminal is known to work, while Windows Command Prompt and Git Bash do not. Improvements are more than welcome! :dizzy:" 265 | ] 266 | } 267 | ], 268 | "press": { 269 | "ul": [ 270 | "[*A GitHub-like contributions calendar, but locally, with all your git commits*, The Changelog](https://changelog.com/github-like-contributions-calendar-locally-git-commits/)" 271 | ] 272 | } 273 | }, 274 | "files": [ 275 | "bin/", 276 | "app/", 277 | "lib/", 278 | "dist/", 279 | "src/", 280 | "scripts/", 281 | "resources/", 282 | "menu/", 283 | "cli.js", 284 | "index.js", 285 | "index.d.ts", 286 | "package-lock.json", 287 | "bloggify.js", 288 | "bloggify.json", 289 | "bloggify/" 290 | ] 291 | } -------------------------------------------------------------------------------- /scripts/init-git-post-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Check dependencies 4 | check_command() { 5 | command -v "$1" > /dev/null 2>&1 || { echo "git-stats hook script requires the \`${1}\` binary in order to run." >&2; exit 1; } 6 | } 7 | 8 | check_command "perl" 9 | check_command "printf" 10 | check_command "git" 11 | 12 | echo "Setting up git-stats hooks."; 13 | 14 | # Create a new global templatedir if there are none 15 | git_templates_dir=$(git config --global --get init.templatedir); 16 | if [ $? -ne 0 ]; then 17 | # Create a new global templatedir if there are none 18 | git_templates_dir="${HOME}/.git-templates" 19 | git config --global init.templatedir "$git_templates_dir" && echo "Set new global git template dir at ${git_templates_dir}" 20 | fi 21 | git_hooks_dir="${git_templates_dir}/hooks" 22 | post_commit_path="${git_hooks_dir}/post-commit" 23 | 24 | mkdir -p "$git_hooks_dir" 25 | 26 | # Create the post-commit file content 27 | hook=$(cat < "$post_commit_path" \ 41 | && chmod +x "$post_commit_path" \ 42 | && echo "Successfully set up git-stats hook at ${post_commit_path}." \ 43 | && exit 0 44 | else 45 | # Remove any previous git-stats hook code blocks 46 | perl -i -0pe 's/(([ \t]*# Copy last commit hash to clipboard on commit\s*(\n.*){5}\s*git-stats --record "\$commit_data"\s*)|([ \t]*### git-stats hook \(begin\) ###\s*(\n.*){7}\s*### git-stats hook \(end\) ###\s*))//g' "$post_commit_path" 47 | printf "%s\n" "$hook" >> "$post_commit_path" \ 48 | && echo "Successfully set up git-stats hook at ${post_commit_path}." \ 49 | && exit 0 50 | fi 51 | 52 | echo "Couldn't set up git-stats hook." 53 | exit 1 54 | -------------------------------------------------------------------------------- /scripts/migration/2.0.0.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | // Dependencies 4 | var ReadJson = require("r-json") 5 | , WriteJson = require("w-json") 6 | , Abs = require("abs") 7 | , Logger = require("bug-killer") 8 | ; 9 | 10 | // Constants 11 | const DATA_FILE = Abs("~/.git-stats"); 12 | 13 | function migrate() { 14 | var data = {}; 15 | 16 | try { 17 | data = ReadJson(DATA_FILE) 18 | } catch (e) { 19 | if (e.code === "ENOENT") { 20 | return; 21 | } 22 | Logger.log(e); 23 | } 24 | 25 | data.commits = data.commits || {}; 26 | var newStats = { commits: data.commits }; 27 | delete data.commits; 28 | Object.keys(data).forEach(function (day) { 29 | var cDay = newStats.commits[day] = newStats.commits[day] || {}; 30 | Object.keys(data[day]).map(function (c) { 31 | Object.keys(data[day][c]).map(function (h) { 32 | cDay[h] = 1; 33 | }); 34 | }); 35 | }); 36 | 37 | WriteJson(DATA_FILE, newStats); 38 | } 39 | 40 | migrate(); 41 | 42 | --------------------------------------------------------------------------------