-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add [NpmStatDownloads] Badge (#9783)
* feat: add npm downloads (by author) badge * Update services/npm-stat/npm-stat-downloads.service.js Co-authored-by: chris48s <chris48s@users.noreply.github.com> * test: add test cases for NpmStatDownloads helper getTotalDownloads * refactor: using dayjs to get from && until date string * feat: remove support of dt --------- Co-authored-by: chris48s <chris48s@users.noreply.github.com>
- Loading branch information
Showing
3 changed files
with
131 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import Joi from 'joi' | ||
import dayjs from 'dayjs' | ||
import { nonNegativeInteger } from '../validators.js' | ||
import { BaseJsonService } from '../index.js' | ||
import { renderDownloadsBadge } from '../downloads.js' | ||
|
||
const schema = Joi.object() | ||
.pattern(Joi.string(), Joi.object().pattern(Joi.string(), nonNegativeInteger)) | ||
.required() | ||
|
||
const intervalMap = { | ||
dw: { interval: 'week' }, | ||
dm: { interval: 'month' }, | ||
dy: { interval: 'year' }, | ||
} | ||
|
||
export default class NpmStatDownloads extends BaseJsonService { | ||
static category = 'downloads' | ||
|
||
static route = { | ||
base: 'npm-stat', | ||
pattern: ':interval(dw|dm|dy)/:author', | ||
} | ||
|
||
static examples = [ | ||
{ | ||
title: 'npm (by author)', | ||
documentation: | ||
'The total number of downloads of npm packages published by the specified author from [npm-stat](https://npm-stat.com).', | ||
namedParams: { interval: 'dy', author: 'dukeluo' }, | ||
staticPreview: this.render({ interval: 'dy', downloadCount: 30000 }), | ||
keywords: ['node'], | ||
}, | ||
] | ||
|
||
static _cacheLength = 21600 | ||
|
||
static defaultBadgeData = { label: 'downloads' } | ||
|
||
static getTotalDownloads(data) { | ||
const add = (x, y) => x + y | ||
const sum = nums => nums.reduce(add, 0) | ||
|
||
return Object.values(data).reduce( | ||
(count, packageDownloads) => count + sum(Object.values(packageDownloads)), | ||
0, | ||
) | ||
} | ||
|
||
static render({ interval, downloads }) { | ||
return renderDownloadsBadge({ | ||
downloads, | ||
interval: intervalMap[interval].interval, | ||
colorOverride: downloads > 0 ? 'brightgreen' : 'red', | ||
}) | ||
} | ||
|
||
async handle({ interval, author }) { | ||
const unit = intervalMap[interval].interval | ||
const today = dayjs() | ||
const until = today.format('YYYY-MM-DD') | ||
const from = today.subtract(1, unit).format('YYYY-MM-DD') | ||
const data = await this._requestJson({ | ||
url: `https://npm-stat.com/api/download-counts?author=${author}&from=${from}&until=${until}`, | ||
schema, | ||
}) | ||
const downloads = this.constructor.getTotalDownloads(data) | ||
|
||
return this.constructor.render({ interval, downloads }) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { test, given } from 'sazerac' | ||
import NpmStatDownloads from './npm-stat-downloads.service.js' | ||
|
||
describe('NpmStatDownloads helpers', function () { | ||
test(NpmStatDownloads.getTotalDownloads, () => { | ||
given({ | ||
'hexo-theme-candelas': { | ||
'2022-12-01': 1, | ||
'2022-12-02': 2, | ||
'2022-12-03': 3, | ||
}, | ||
'@dukeluo/fanjs': { | ||
'2022-12-01': 10, | ||
'2022-12-02': 20, | ||
'2022-12-03': 30, | ||
}, | ||
'eslint-plugin-check-file': { | ||
'2022-12-01': 100, | ||
'2022-12-02': 200, | ||
'2022-12-03': 300, | ||
}, | ||
}).expect(666) | ||
given({}).expect(0) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import { isMetricOverTimePeriod } from '../test-validators.js' | ||
import { createServiceTester } from '../tester.js' | ||
export const t = await createServiceTester() | ||
|
||
t.create('weekly downloads of npm author dukeluo') | ||
.get('/dw/dukeluo.json') | ||
.expectBadge({ | ||
label: 'downloads', | ||
message: isMetricOverTimePeriod, | ||
color: 'brightgreen', | ||
}) | ||
|
||
t.create('monthly downloads of npm author dukeluo') | ||
.get('/dm/dukeluo.json') | ||
.expectBadge({ | ||
label: 'downloads', | ||
message: isMetricOverTimePeriod, | ||
color: 'brightgreen', | ||
}) | ||
|
||
t.create('yearly downloads of npm author dukeluo') | ||
.get('/dy/dukeluo.json') | ||
.expectBadge({ | ||
label: 'downloads', | ||
message: isMetricOverTimePeriod, | ||
color: 'brightgreen', | ||
}) | ||
|
||
t.create('downloads of unknown npm package author') | ||
.get('/dy/npm-api-does-not-have-this-package-author.json') | ||
.expectBadge({ | ||
label: 'downloads', | ||
message: '0/year', | ||
color: 'red', | ||
}) |