@lizardbyte/contribkit 2025.922.2626 → 2026.518.124816

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # ContribKit
2
2
 
3
3
  [![GitHub stars](https://img.shields.io/github/stars/lizardbyte/contribkit.svg?logo=github&style=for-the-badge)](https://github.com/LizardByte/contribkit)
4
- [![GitHub Workflow Status (CI)](https://img.shields.io/github/actions/workflow/status/lizardbyte/contribkit/ci.yml.svg?branch=master&label=CI%20build&logo=github&style=for-the-badge)](https://github.com/LizardByte/contribkit/actions/workflows/CI.yml?query=branch%3Amaster)
4
+ [![GitHub Workflow Status (CI)](https://img.shields.io/github/actions/workflow/status/lizardbyte/contribkit/_ci-node.yml.svg?branch=master&label=CI%20build&logo=github&style=for-the-badge)](https://github.com/LizardByte/contribkit/actions/workflows/_ci-node.yml?query=branch%3Amaster)
5
5
  [![Codecov](https://img.shields.io/codecov/c/gh/LizardByte/contribkit?token=WBivqQDwFw&style=for-the-badge&logo=codecov&label=codecov)](https://codecov.io/gh/LizardByte/contribkit)
6
6
  [![NPM Monthly Downloads](https://img.shields.io/npm/dm/%40lizardbyte%2Fcontribkit?style=for-the-badge&logo=npm&label=npm%20downloads/m)](https://www.npmjs.com/package/@lizardbyte/contribkit)
7
7
  [![NPM Version](https://img.shields.io/npm/v/%40lizardbyte%2Fcontribkit?style=for-the-badge&logo=npm&label=npm%20version)](https://www.npmjs.com/package/@lizardbyte/contribkit)
@@ -13,7 +13,8 @@ Supports:
13
13
 
14
14
  - Contributors:
15
15
  - [**CrowdIn**](https://crowdin.com)
16
- - [**GitHub**](https://github.com)
16
+ - [**GitHub Contributors**](https://github.com) (contributors to a specific repository)
17
+ - [**GitHub Contributions**](https://github.com) (merged PRs aggregated by repository owner across all repos for a single user)
17
18
  - [**Gitlab**](https://gitlab.com)
18
19
  - Sponsors:
19
20
  - [**GitHub Sponsors**](https://github.com/sponsors)
@@ -37,11 +38,25 @@ CONTRIBKIT_CROWDIN_MIN_TRANSLATIONS=1
37
38
 
38
39
  ; GitHubContributors provider.
39
40
  ; Token requires the `public_repo` and `read:user` scopes.
41
+ ; This provider tracks all contributors to a specific repository.
40
42
  CONTRIBKIT_GITHUB_CONTRIBUTORS_TOKEN=
41
43
  CONTRIBKIT_GITHUB_CONTRIBUTORS_LOGIN=
42
44
  CONTRIBKIT_GITHUB_CONTRIBUTORS_MIN=1
43
45
  CONTRIBKIT_GITHUB_CONTRIBUTORS_REPO=
44
46
 
47
+ ; GitHubContributions provider.
48
+ ; Token requires the `read:user` scope.
49
+ ; This provider aggregates merged pull requests across all repositories by repository owner (user or organization).
50
+ ; Each owner appears once with the total merged PRs you authored to their repos.
51
+ ; Avatar and link point to the owner (or to the repo if only one repo per owner).
52
+ ; Only merged PRs are counted - open or closed-without-merge PRs are excluded.
53
+ CONTRIBKIT_GITHUB_CONTRIBUTIONS_TOKEN=
54
+ CONTRIBKIT_GITHUB_CONTRIBUTIONS_LOGIN=
55
+ ; Optional: Cap the maximum contribution count per org/user (useful for circles visualization)
56
+ CONTRIBKIT_GITHUB_CONTRIBUTIONS_MAX=
57
+ ; Optional: Apply logarithmic scaling to reduce dominance of high contributors (true/false)
58
+ CONTRIBKIT_GITHUB_CONTRIBUTIONS_LOGARITHMIC=
59
+
45
60
  ; GitlabContributors provider.
46
61
  ; Token requires the `read_api` and `read_user` scopes.
47
62
  CONTRIBKIT_GITLAB_CONTRIBUTORS_TOKEN=
@@ -96,9 +111,26 @@ CONTRIBKIT_LIBERAPAY_LOGIN=
96
111
  > This will require different env variables to be set for each provider, and to be created from separate
97
112
  > commands.
98
113
 
114
+ #### GitHub Provider Options
115
+
116
+ There are two GitHub contributor providers available:
117
+
118
+ - **GitHubContributors**: Tracks all contributors to a specific repository (e.g., `owner/repo`). Each contributor appears once with their actual contribution count to that repository.
119
+ - **GitHubContributions**: Aggregates a single user's **merged pull requests** across all repositories, grouped by repository owner (user or organization). Each owner appears once with the total merged PRs. The avatar and link point to the owner (or to the specific repo if only one repo per owner).
120
+
121
+ Use **GitHubContributors** when you want to showcase everyone who has contributed to your project with their contribution counts.
122
+ Use **GitHubContributions** when you want to understand where a single user's completed contributions (merged PRs) have gone, without overwhelming duplicates per repo under the same owner.
123
+
124
+ **GitHubContributions accuracy**:
125
+ - Counts only **merged** pull requests - open or closed-without-merge PRs are excluded
126
+ - Discovers repos via **2 sources**:
127
+ 1. **contributionsCollection** - Yearly commit timeline (full history) for discovering repositories you have committed to
128
+ 2. **Search API** - Repositories where you have merged PRs (`is:pr is:merged author:login`)
129
+ - When an owner has only one repo, the link points to that repo; otherwise to the owner profile
130
+
99
131
  Run:
100
132
 
101
- ```base
133
+ ```bash
102
134
  npx contribkit
103
135
  ```
104
136
 
@@ -133,6 +165,11 @@ export default defineConfig({
133
165
  // ...
134
166
  },
135
167
 
168
+ // For contributor providers:
169
+ githubContributions: {
170
+ login: 'username',
171
+ },
172
+
136
173
  // Rendering configs
137
174
  width: 800,
138
175
  renderer: 'tiers', // or 'circles'
@@ -43,6 +43,12 @@ class Queue {
43
43
 
44
44
  this.#head = this.#head.next;
45
45
  this.#size--;
46
+
47
+ // Clean up tail reference when queue becomes empty
48
+ if (!this.#head) {
49
+ this.#tail = undefined;
50
+ }
51
+
46
52
  return current.value;
47
53
  }
48
54
 
@@ -84,61 +90,70 @@ class Queue {
84
90
  }
85
91
 
86
92
  function pLimit(concurrency) {
93
+ let rejectOnClear = false;
94
+
95
+ if (typeof concurrency === 'object') {
96
+ ({concurrency, rejectOnClear = false} = concurrency);
97
+ }
98
+
87
99
  validateConcurrency(concurrency);
88
100
 
101
+ if (typeof rejectOnClear !== 'boolean') {
102
+ throw new TypeError('Expected `rejectOnClear` to be a boolean');
103
+ }
104
+
89
105
  const queue = new Queue();
90
106
  let activeCount = 0;
91
107
 
92
108
  const resumeNext = () => {
109
+ // Process the next queued function if we're under the concurrency limit
93
110
  if (activeCount < concurrency && queue.size > 0) {
94
- queue.dequeue()();
95
- // Since `pendingCount` has been decreased by one, increase `activeCount` by one.
96
111
  activeCount++;
112
+ queue.dequeue().run();
97
113
  }
98
114
  };
99
115
 
100
116
  const next = () => {
101
117
  activeCount--;
102
-
103
118
  resumeNext();
104
119
  };
105
120
 
106
121
  const run = async (function_, resolve, arguments_) => {
122
+ // Execute the function and capture the result promise
107
123
  const result = (async () => function_(...arguments_))();
108
124
 
125
+ // Resolve immediately with the promise (don't wait for completion)
109
126
  resolve(result);
110
127
 
128
+ // Wait for the function to complete (success or failure)
129
+ // We catch errors here to prevent unhandled rejections,
130
+ // but the original promise rejection is preserved for the caller
111
131
  try {
112
132
  await result;
113
133
  } catch {}
114
134
 
135
+ // Decrement active count and process next queued function
115
136
  next();
116
137
  };
117
138
 
118
- const enqueue = (function_, resolve, arguments_) => {
119
- // Queue `internalResolve` instead of the `run` function
120
- // to preserve asynchronous context.
121
- new Promise(internalResolve => {
122
- queue.enqueue(internalResolve);
123
- }).then(
124
- run.bind(undefined, function_, resolve, arguments_),
125
- );
126
-
127
- (async () => {
128
- // This function needs to wait until the next microtask before comparing
129
- // `activeCount` to `concurrency`, because `activeCount` is updated asynchronously
130
- // after the `internalResolve` function is dequeued and called. The comparison in the if-statement
131
- // needs to happen asynchronously as well to get an up-to-date value for `activeCount`.
132
- await Promise.resolve();
133
-
134
- if (activeCount < concurrency) {
135
- resumeNext();
136
- }
137
- })();
139
+ const enqueue = (function_, resolve, reject, arguments_) => {
140
+ const queueItem = {reject};
141
+
142
+ // Queue the internal resolve function instead of the run function
143
+ // to preserve the asynchronous execution context.
144
+ new Promise(internalResolve => { // eslint-disable-line promise/param-names
145
+ queueItem.run = internalResolve;
146
+ queue.enqueue(queueItem);
147
+ }).then(run.bind(undefined, function_, resolve, arguments_)); // eslint-disable-line promise/prefer-await-to-then
148
+
149
+ // Start processing immediately if we haven't reached the concurrency limit
150
+ if (activeCount < concurrency) {
151
+ resumeNext();
152
+ }
138
153
  };
139
154
 
140
- const generator = (function_, ...arguments_) => new Promise(resolve => {
141
- enqueue(function_, resolve, arguments_);
155
+ const generator = (function_, ...arguments_) => new Promise((resolve, reject) => {
156
+ enqueue(function_, resolve, reject, arguments_);
142
157
  });
143
158
 
144
159
  Object.defineProperties(generator, {
@@ -150,7 +165,16 @@ function pLimit(concurrency) {
150
165
  },
151
166
  clearQueue: {
152
167
  value() {
153
- queue.clear();
168
+ if (!rejectOnClear) {
169
+ queue.clear();
170
+ return;
171
+ }
172
+
173
+ const abortError = AbortSignal.abort().reason;
174
+
175
+ while (queue.size > 0) {
176
+ queue.dequeue().reject(abortError);
177
+ }
154
178
  },
155
179
  },
156
180
  concurrency: {
@@ -168,6 +192,12 @@ function pLimit(concurrency) {
168
192
  });
169
193
  },
170
194
  },
195
+ map: {
196
+ async value(iterable, function_) {
197
+ const promises = Array.from(iterable, (value, index) => this(function_, value, index));
198
+ return Promise.all(promises);
199
+ },
200
+ },
171
201
  });
172
202
 
173
203
  return generator;
@@ -193,48 +193,6 @@ function requireLodash_escaperegexp () {
193
193
  return lodash_escaperegexp;
194
194
  }
195
195
 
196
- /**
197
- * lodash 4.0.0 (Custom Build) <https://lodash.com/>
198
- * Build: `lodash modularize exports="npm" -o ./`
199
- * Copyright 2012-2016 The Dojo Foundation <http://dojofoundation.org/>
200
- * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
201
- * Copyright 2009-2016 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
202
- * Available under MIT license <https://lodash.com/license>
203
- */
204
-
205
- var lodash_isnil;
206
- var hasRequiredLodash_isnil;
207
-
208
- function requireLodash_isnil () {
209
- if (hasRequiredLodash_isnil) return lodash_isnil;
210
- hasRequiredLodash_isnil = 1;
211
- /**
212
- * Checks if `value` is `null` or `undefined`.
213
- *
214
- * @static
215
- * @memberOf _
216
- * @category Lang
217
- * @param {*} value The value to check.
218
- * @returns {boolean} Returns `true` if `value` is nullish, else `false`.
219
- * @example
220
- *
221
- * _.isNil(null);
222
- * // => true
223
- *
224
- * _.isNil(void 0);
225
- * // => true
226
- *
227
- * _.isNil(NaN);
228
- * // => false
229
- */
230
- function isNil(value) {
231
- return value == null;
232
- }
233
-
234
- lodash_isnil = isNil;
235
- return lodash_isnil;
236
- }
237
-
238
196
  var hasRequiredParserOptions;
239
197
 
240
198
  function requireParserOptions () {
@@ -246,7 +204,6 @@ function requireParserOptions () {
246
204
  Object.defineProperty(ParserOptions, "__esModule", { value: true });
247
205
  ParserOptions.ParserOptions = void 0;
248
206
  const lodash_escaperegexp_1 = __importDefault(requireLodash_escaperegexp());
249
- const lodash_isnil_1 = __importDefault(requireLodash_isnil());
250
207
  let ParserOptions$1 = class ParserOptions {
251
208
  escapedDelimiter;
252
209
  objectMode = true;
@@ -278,7 +235,7 @@ function requireParserOptions () {
278
235
  }
279
236
  this.escapedDelimiter = (0, lodash_escaperegexp_1.default)(this.delimiter);
280
237
  this.escapeChar = this.escape ?? this.quote;
281
- this.supportsComments = !(0, lodash_isnil_1.default)(this.comment);
238
+ this.supportsComments = this.comment != null;
282
239
  this.NEXT_TOKEN_REGEXP = new RegExp(`([^\\s]|\\r\\n|\\n|\\r|${this.escapedDelimiter})`);
283
240
  if (this.maxRows > 0) {
284
241
  this.limitRows = true;
@@ -296,170 +253,6 @@ var transforms = {};
296
253
 
297
254
  var RowTransformerValidator = {};
298
255
 
299
- /**
300
- * Lodash (Custom Build) <https://lodash.com/>
301
- * Build: `lodash modularize exports="npm" -o ./`
302
- * Copyright JS Foundation and other contributors <https://js.foundation/>
303
- * Released under MIT license <https://lodash.com/license>
304
- * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
305
- * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
306
- */
307
-
308
- var lodash_isfunction;
309
- var hasRequiredLodash_isfunction;
310
-
311
- function requireLodash_isfunction () {
312
- if (hasRequiredLodash_isfunction) return lodash_isfunction;
313
- hasRequiredLodash_isfunction = 1;
314
- /** `Object#toString` result references. */
315
- var asyncTag = '[object AsyncFunction]',
316
- funcTag = '[object Function]',
317
- genTag = '[object GeneratorFunction]',
318
- nullTag = '[object Null]',
319
- proxyTag = '[object Proxy]',
320
- undefinedTag = '[object Undefined]';
321
-
322
- /** Detect free variable `global` from Node.js. */
323
- var freeGlobal = typeof commonjsGlobal == 'object' && commonjsGlobal && commonjsGlobal.Object === Object && commonjsGlobal;
324
-
325
- /** Detect free variable `self`. */
326
- var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
327
-
328
- /** Used as a reference to the global object. */
329
- var root = freeGlobal || freeSelf || Function('return this')();
330
-
331
- /** Used for built-in method references. */
332
- var objectProto = Object.prototype;
333
-
334
- /** Used to check objects for own properties. */
335
- var hasOwnProperty = objectProto.hasOwnProperty;
336
-
337
- /**
338
- * Used to resolve the
339
- * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
340
- * of values.
341
- */
342
- var nativeObjectToString = objectProto.toString;
343
-
344
- /** Built-in value references. */
345
- var Symbol = root.Symbol,
346
- symToStringTag = Symbol ? Symbol.toStringTag : undefined;
347
-
348
- /**
349
- * The base implementation of `getTag` without fallbacks for buggy environments.
350
- *
351
- * @private
352
- * @param {*} value The value to query.
353
- * @returns {string} Returns the `toStringTag`.
354
- */
355
- function baseGetTag(value) {
356
- if (value == null) {
357
- return value === undefined ? undefinedTag : nullTag;
358
- }
359
- return (symToStringTag && symToStringTag in Object(value))
360
- ? getRawTag(value)
361
- : objectToString(value);
362
- }
363
-
364
- /**
365
- * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
366
- *
367
- * @private
368
- * @param {*} value The value to query.
369
- * @returns {string} Returns the raw `toStringTag`.
370
- */
371
- function getRawTag(value) {
372
- var isOwn = hasOwnProperty.call(value, symToStringTag),
373
- tag = value[symToStringTag];
374
-
375
- try {
376
- value[symToStringTag] = undefined;
377
- var unmasked = true;
378
- } catch (e) {}
379
-
380
- var result = nativeObjectToString.call(value);
381
- if (unmasked) {
382
- if (isOwn) {
383
- value[symToStringTag] = tag;
384
- } else {
385
- delete value[symToStringTag];
386
- }
387
- }
388
- return result;
389
- }
390
-
391
- /**
392
- * Converts `value` to a string using `Object.prototype.toString`.
393
- *
394
- * @private
395
- * @param {*} value The value to convert.
396
- * @returns {string} Returns the converted string.
397
- */
398
- function objectToString(value) {
399
- return nativeObjectToString.call(value);
400
- }
401
-
402
- /**
403
- * Checks if `value` is classified as a `Function` object.
404
- *
405
- * @static
406
- * @memberOf _
407
- * @since 0.1.0
408
- * @category Lang
409
- * @param {*} value The value to check.
410
- * @returns {boolean} Returns `true` if `value` is a function, else `false`.
411
- * @example
412
- *
413
- * _.isFunction(_);
414
- * // => true
415
- *
416
- * _.isFunction(/abc/);
417
- * // => false
418
- */
419
- function isFunction(value) {
420
- if (!isObject(value)) {
421
- return false;
422
- }
423
- // The use of `Object#toString` avoids issues with the `typeof` operator
424
- // in Safari 9 which returns 'object' for typed arrays and other constructors.
425
- var tag = baseGetTag(value);
426
- return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;
427
- }
428
-
429
- /**
430
- * Checks if `value` is the
431
- * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
432
- * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
433
- *
434
- * @static
435
- * @memberOf _
436
- * @since 0.1.0
437
- * @category Lang
438
- * @param {*} value The value to check.
439
- * @returns {boolean} Returns `true` if `value` is an object, else `false`.
440
- * @example
441
- *
442
- * _.isObject({});
443
- * // => true
444
- *
445
- * _.isObject([1, 2, 3]);
446
- * // => true
447
- *
448
- * _.isObject(_.noop);
449
- * // => true
450
- *
451
- * _.isObject(null);
452
- * // => false
453
- */
454
- function isObject(value) {
455
- var type = typeof value;
456
- return value != null && (type == 'object' || type == 'function');
457
- }
458
-
459
- lodash_isfunction = isFunction;
460
- return lodash_isfunction;
461
- }
462
-
463
256
  var types = {};
464
257
 
465
258
  var hasRequiredTypes;
@@ -486,15 +279,10 @@ var hasRequiredRowTransformerValidator;
486
279
  function requireRowTransformerValidator () {
487
280
  if (hasRequiredRowTransformerValidator) return RowTransformerValidator;
488
281
  hasRequiredRowTransformerValidator = 1;
489
- var __importDefault = (RowTransformerValidator && RowTransformerValidator.__importDefault) || function (mod) {
490
- return (mod && mod.__esModule) ? mod : { "default": mod };
491
- };
492
282
  Object.defineProperty(RowTransformerValidator, "__esModule", { value: true });
493
283
  RowTransformerValidator.RowTransformerValidator = void 0;
494
- const lodash_isfunction_1 = __importDefault(requireLodash_isfunction());
495
284
  const types_1 = requireTypes();
496
285
  let RowTransformerValidator$1 = class RowTransformerValidator {
497
- // eslint-disable-next-line @typescript-eslint/no-shadow
498
286
  static createTransform(transformFunction) {
499
287
  if ((0, types_1.isSyncTransform)(transformFunction)) {
500
288
  return (row, cb) => {
@@ -531,13 +319,13 @@ function requireRowTransformerValidator () {
531
319
  _rowTransform = null;
532
320
  _rowValidator = null;
533
321
  set rowTransform(transformFunction) {
534
- if (!(0, lodash_isfunction_1.default)(transformFunction)) {
322
+ if (typeof transformFunction !== 'function') {
535
323
  throw new TypeError('The transform should be a function');
536
324
  }
537
325
  this._rowTransform = RowTransformerValidator.createTransform(transformFunction);
538
326
  }
539
327
  set rowValidator(validateFunction) {
540
- if (!(0, lodash_isfunction_1.default)(validateFunction)) {
328
+ if (typeof validateFunction !== 'function') {
541
329
  throw new TypeError('The validate should be a function');
542
330
  }
543
331
  this._rowValidator = RowTransformerValidator.createValidator(validateFunction);
@@ -581,45 +369,6 @@ function requireRowTransformerValidator () {
581
369
 
582
370
  var HeaderTransformer = {};
583
371
 
584
- /**
585
- * lodash 3.0.1 (Custom Build) <https://lodash.com/>
586
- * Build: `lodash modern modularize exports="npm" -o ./`
587
- * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
588
- * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
589
- * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
590
- * Available under MIT license <https://lodash.com/license>
591
- */
592
-
593
- var lodash_isundefined;
594
- var hasRequiredLodash_isundefined;
595
-
596
- function requireLodash_isundefined () {
597
- if (hasRequiredLodash_isundefined) return lodash_isundefined;
598
- hasRequiredLodash_isundefined = 1;
599
- /**
600
- * Checks if `value` is `undefined`.
601
- *
602
- * @static
603
- * @memberOf _
604
- * @category Lang
605
- * @param {*} value The value to check.
606
- * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`.
607
- * @example
608
- *
609
- * _.isUndefined(void 0);
610
- * // => true
611
- *
612
- * _.isUndefined(null);
613
- * // => false
614
- */
615
- function isUndefined(value) {
616
- return value === undefined;
617
- }
618
-
619
- lodash_isundefined = isUndefined;
620
- return lodash_isundefined;
621
- }
622
-
623
372
  /**
624
373
  * lodash (Custom Build) <https://lodash.com/>
625
374
  * Build: `lodash modularize exports="npm" -o ./`
@@ -3885,8 +3634,6 @@ function requireHeaderTransformer () {
3885
3634
  };
3886
3635
  Object.defineProperty(HeaderTransformer, "__esModule", { value: true });
3887
3636
  HeaderTransformer.HeaderTransformer = void 0;
3888
- const lodash_isundefined_1 = __importDefault(requireLodash_isundefined());
3889
- const lodash_isfunction_1 = __importDefault(requireLodash_isfunction());
3890
3637
  const lodash_uniq_1 = __importDefault(requireLodash_uniq());
3891
3638
  const lodash_groupby_1 = __importDefault(requireLodash_groupby());
3892
3639
  let HeaderTransformer$1 = class HeaderTransformer {
@@ -3905,7 +3652,7 @@ function requireHeaderTransformer () {
3905
3652
  else if (Array.isArray(parserOptions.headers)) {
3906
3653
  this.setHeaders(parserOptions.headers);
3907
3654
  }
3908
- else if ((0, lodash_isfunction_1.default)(parserOptions.headers)) {
3655
+ else if (typeof parserOptions.headers === 'function') {
3909
3656
  this.headersTransform = parserOptions.headers;
3910
3657
  }
3911
3658
  }
@@ -3968,10 +3715,9 @@ function requireHeaderTransformer () {
3968
3715
  const { headers, headersLength } = this;
3969
3716
  for (let i = 0; i < headersLength; i += 1) {
3970
3717
  const header = headers[i];
3971
- if (!(0, lodash_isundefined_1.default)(header)) {
3718
+ if (header !== undefined) {
3972
3719
  const val = row[i];
3973
- // eslint-disable-next-line no-param-reassign
3974
- if ((0, lodash_isundefined_1.default)(val)) {
3720
+ if (val === undefined) {
3975
3721
  rowMap[header] = '';
3976
3722
  }
3977
3723
  else {
@@ -4851,13 +4597,23 @@ function requireSrc () {
4851
4597
  }) : function(o, v) {
4852
4598
  o["default"] = v;
4853
4599
  });
4854
- var __importStar = (src && src.__importStar) || function (mod) {
4855
- if (mod && mod.__esModule) return mod;
4856
- var result = {};
4857
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
4858
- __setModuleDefault(result, mod);
4859
- return result;
4860
- };
4600
+ var __importStar = (src && src.__importStar) || (function () {
4601
+ var ownKeys = function(o) {
4602
+ ownKeys = Object.getOwnPropertyNames || function (o) {
4603
+ var ar = [];
4604
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
4605
+ return ar;
4606
+ };
4607
+ return ownKeys(o);
4608
+ };
4609
+ return function (mod) {
4610
+ if (mod && mod.__esModule) return mod;
4611
+ var result = {};
4612
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
4613
+ __setModuleDefault(result, mod);
4614
+ return result;
4615
+ };
4616
+ })();
4861
4617
  var __exportStar = (src && src.__exportStar) || function(m, exports) {
4862
4618
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
4863
4619
  };
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import cac from 'cac';
2
- import { S as SvgComposer, i as generateBadge, p as partitionTiers, t as tierPresets, v as version, l as loadConfig, k as resolveProviders, j as guessProviders, r as resolveAvatars, q as outputFormats, s as svgToPng, g as svgToWebp } from './shared/contribkit.DAlakhwL.mjs';
2
+ import { S as SvgComposer, h as generateBadge, p as partitionTiers, t as tierPresets, v as version, l as loadConfig, n as resolveProviders, i as guessProviders, k as resolveAvatars, o as outputFormats, s as svgToPng, q as svgToWebp } from './shared/contribkit.DYospa65.mjs';
3
3
  import fs from 'node:fs';
4
4
  import fsp from 'node:fs/promises';
5
5
  import { resolve, dirname, relative, join } from 'node:path';
package/dist/index.d.mts CHANGED
@@ -83,7 +83,7 @@ interface Sponsorship {
83
83
  }
84
84
  declare const outputFormats: readonly ["svg", "png", "webp", "json"];
85
85
  type OutputFormat = typeof outputFormats[number];
86
- type ProviderName = 'github' | 'patreon' | 'opencollective' | 'afdian' | 'polar' | 'liberapay' | 'githubContributors' | 'gitlabContributors' | 'crowdinContributors';
86
+ type ProviderName = 'github' | 'patreon' | 'opencollective' | 'afdian' | 'polar' | 'liberapay' | 'githubContributors' | 'gitlabContributors' | 'crowdinContributors' | 'githubContributions';
87
87
  type GitHubAccountType = 'user' | 'organization';
88
88
  interface ProvidersConfig {
89
89
  github?: {
@@ -278,6 +278,36 @@ interface ProvidersConfig {
278
278
  */
279
279
  minTranslations?: number;
280
280
  };
281
+ githubContributions?: {
282
+ /**
283
+ * GitHub user login to fetch contributions for.
284
+ *
285
+ * Will read from `CONTRIBKIT_GITHUB_CONTRIBUTIONS_LOGIN` environment variable if not set.
286
+ */
287
+ login?: string;
288
+ /**
289
+ * GitHub Token that has access to read user contributions.
290
+ *
291
+ * Will read from `CONTRIBKIT_GITHUB_CONTRIBUTIONS_TOKEN` environment variable if not set.
292
+ *
293
+ * @deprecated It's not recommended set this value directly, pass from env or use `.env` file.
294
+ */
295
+ token?: string;
296
+ /**
297
+ * Cap the maximum contribution count per organization/user.
298
+ * Useful to prevent one dominant contributor from overshadowing others in visualizations.
299
+ *
300
+ * @example 100 // Cap all contributions at 100 PRs max
301
+ */
302
+ maxContributions?: number;
303
+ /**
304
+ * Apply logarithmic scaling to contribution counts.
305
+ * Useful to reduce the visual dominance of high contributors while maintaining relative differences.
306
+ *
307
+ * @default false
308
+ */
309
+ logarithmicScaling?: boolean;
310
+ };
281
311
  }
282
312
  interface ContribkitRenderOptions {
283
313
  /**
@@ -557,6 +587,7 @@ declare const ProvidersMap: {
557
587
  polar: Provider;
558
588
  liberapay: Provider;
559
589
  githubContributors: Provider;
590
+ githubContributions: Provider;
560
591
  gitlabContributors: Provider;
561
592
  crowdinContributors: Provider;
562
593
  };
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- export { F as FALLBACK_AVATAR, G as GitHubProvider, P as ProvidersMap, S as SvgComposer, c as defaultConfig, b as defaultInlineCSS, a as defaultTiers, d as defineConfig, n as fetchGitHubSponsors, m as fetchSponsors, h as genSvgImage, i as generateBadge, j as guessProviders, l as loadConfig, o as makeQuery, q as outputFormats, p as partitionTiers, e as presets, f as resizeImage, r as resolveAvatars, k as resolveProviders, s as svgToPng, g as svgToWebp, t as tierPresets } from './shared/contribkit.DAlakhwL.mjs';
1
+ export { F as FALLBACK_AVATAR, G as GitHubProvider, P as ProvidersMap, S as SvgComposer, d as defaultConfig, a as defaultInlineCSS, b as defaultTiers, c as defineConfig, f as fetchGitHubSponsors, e as fetchSponsors, g as genSvgImage, h as generateBadge, i as guessProviders, l as loadConfig, m as makeQuery, o as outputFormats, p as partitionTiers, j as presets, r as resizeImage, k as resolveAvatars, n as resolveProviders, s as svgToPng, q as svgToWebp, t as tierPresets } from './shared/contribkit.DYospa65.mjs';
2
2
  import 'unconfig';
3
3
  import 'node:process';
4
4
  import 'dotenv';