From f13cd981f9516401f25752323830d0f81a4102d4 Mon Sep 17 00:00:00 2001 From: Prashant Date: Mon, 4 Sep 2023 20:53:31 +0530 Subject: [PATCH] add dub score badge service --- services/dub/dub-score.service.js | 42 +++++++++++++++++++++++++++++++ services/dub/dub-score.tester.js | 26 +++++++++++++++++++ services/test-validators.js | 11 ++++++++ 3 files changed, 79 insertions(+) create mode 100644 services/dub/dub-score.service.js create mode 100644 services/dub/dub-score.tester.js diff --git a/services/dub/dub-score.service.js b/services/dub/dub-score.service.js new file mode 100644 index 0000000000000..72f31513a9956 --- /dev/null +++ b/services/dub/dub-score.service.js @@ -0,0 +1,42 @@ +import Joi from 'joi' +import { BaseJsonService } from '../index.js' +import { colorScale } from '../color-formatters.js' + +const schema = Joi.object({ + score: Joi.number().required(), +}) + +export default class DubScore extends BaseJsonService { + static category = 'rating' + + static route = { base: 'dub/score', pattern: ':packageName' } + + static examples = [ + { + title: 'DUB SCORE', + namedParams: { packageName: 'vibe-d' }, + staticPreview: this.render({ score: 4.5 }), + }, + ] + + static defaultBadgeData = { label: 'SCORE' } + + static render({ score }) { + return { + label: 'SCORE', + color: colorScale([1, 2, 3, 4, 5])(score), + message: score, + } + } + + async fetch({ packageName }) { + const url = `https://code.dlang.org/api/packages/${packageName}/stats` + return this._requestJson({ schema, url }) + } + + async handle({ packageName }) { + let { score } = await this.fetch({ packageName }) + score = score.toFixed(1) + return this.constructor.render({ score }) + } +} diff --git a/services/dub/dub-score.tester.js b/services/dub/dub-score.tester.js new file mode 100644 index 0000000000000..2f6e704779a66 --- /dev/null +++ b/services/dub/dub-score.tester.js @@ -0,0 +1,26 @@ +import Joi from 'joi' +import { isWithinRange } from '../test-validators.js' +import { createServiceTester } from '../tester.js' + +export const t = await createServiceTester() + +const isScoreColor = Joi.equal( + 'red', + 'orange', + 'yellow', + 'yellowgreen', + 'green', + 'brightgreen', +) + +t.create('version (valid)') + .get('/vibe-d.json') + .expectBadge({ + label: 'SCORE', + message: isWithinRange(0, 5), + color: isScoreColor, + }) + +t.create('version (not found)') + .get('/not-a-package.json') + .expectBadge({ label: 'SCORE', message: 'not found' }) diff --git a/services/test-validators.js b/services/test-validators.js index 489cce69f1ae6..a7d689505299f 100644 --- a/services/test-validators.js +++ b/services/test-validators.js @@ -178,6 +178,16 @@ const isCurrency = withRegex( /(?=.*\d)^\$?(([1-9]\d{0,2}(,\d{3})*)|0)?(\.\d{1,2})?$/, ) +/** + * Returns a Joi schema that validates strings that represent numbers within the range [start, end]. + * + * @param {number} start - The lower bound of the range (inclusive) + * @param {number} end - The upper bound of the range (inclusive) + * @returns {Joi.StringSchema} A Joi schema that uses a regular expression to check if the string is a number in the range + */ +const isWithinRange = (start, end) => + withRegex(new RegExp(`^([${start}-${end - 1}](.[0-9])?)|(${end}(.0)?)$`)) + export { isSemver, isVPlusTripleDottedVersion, @@ -214,4 +224,5 @@ export { isOrdinalNumberDaily, isHumanized, isCurrency, + isWithinRange, }