From 845da2f0a56d750a7cbb791ec38b45cf1e804059 Mon Sep 17 00:00:00 2001 From: TZ Date: Sun, 13 Jun 2021 10:18:16 +0800 Subject: [PATCH] feat: support npm rating --- services/npm/npm-rating.service.js | 70 ++++++++++++++++++++++++++++++ services/npm/npm-rating.tester.js | 42 ++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 services/npm/npm-rating.service.js create mode 100644 services/npm/npm-rating.tester.js diff --git a/services/npm/npm-rating.service.js b/services/npm/npm-rating.service.js new file mode 100644 index 0000000000000..8b27bf90d9730 --- /dev/null +++ b/services/npm/npm-rating.service.js @@ -0,0 +1,70 @@ +'use strict' + +const Joi = require('joi') +const { starRating } = require('../text-formatters') +const { BaseJsonService } = require('..') + +// https://api-docs.npms.io/#api-Package-GetPackageInfo +const responseSchema = Joi.object({ + score: Joi.object({ + final: Joi.number().required(), + detail: Joi.object({ + maintenance: Joi.number().required(), + popularity: Joi.number().required(), + quality: Joi.number().required(), + }), + }), +}).required() + +module.exports = class NpmRating extends BaseJsonService { + static category = 'rating' + + static route = { + base: 'npm', + pattern: + 'rating/:type(maintenance|popularity|quality)?/:scope(@.+)?/:packageName', + } + + static examples = [ + { + title: 'npm rating', + namedParams: { packageName: 'egg' }, + staticPreview: this.render({ score: 0.9711 }), + keywords: ['node'], + }, + { + title: 'npm rating (maintenance)', + namedParams: { type: 'maintenance', packageName: 'command' }, + staticPreview: this.render({ type: 'maintenance', score: 0.222 }), + keywords: ['node'], + }, + ] + + static defaultBadgeData = { + label: 'Rating', + } + + static render({ type, score }) { + return { + label: !type ? 'Rating' : type[0].toUpperCase() + type.substring(1), + message: starRating(score * 5), + color: score > 0.3 ? 'brightgreen' : 'red', + } + } + + async handle({ type, scope, packageName }) { + const slug = scope ? `${scope}/${packageName}` : packageName + const url = `https://api.npms.io/v2/package/${encodeURIComponent(slug)}` + + const json = await this._requestJson({ + schema: responseSchema, + url, + errorMessages: { 404: 'package not found or too new' }, + }) + + let score = json.score.final + if (type) score = json.score.detail[type] + + return this.constructor.render({ type, score }) + } +} diff --git a/services/npm/npm-rating.tester.js b/services/npm/npm-rating.tester.js new file mode 100644 index 0000000000000..f31c595d49274 --- /dev/null +++ b/services/npm/npm-rating.tester.js @@ -0,0 +1,42 @@ +'use strict' + +const { isStarRating } = require('../test-validators') +const t = (module.exports = require('../tester').createServiceTester()) + +t.create('score of vue').get('/rating/vue.json').expectBadge({ + label: 'Rating', + message: isStarRating, + color: 'brightgreen', +}) + +t.create('score of @vue/cli').get('/rating/@vue/cli.json').expectBadge({ + label: 'Rating', + message: isStarRating, + color: 'brightgreen', +}) + +t.create('maintenance of vue').get('/rating/maintenance/vue.json').expectBadge({ + label: 'Maintenance', + message: isStarRating, + color: 'brightgreen', +}) + +t.create('popularity of vue').get('/rating/popularity/vue.json').expectBadge({ + label: 'Popularity', + message: isStarRating, + color: 'brightgreen', +}) + +t.create('quality of vue').get('/rating/quality/vue.json').expectBadge({ + label: 'Quality', + message: isStarRating, + color: 'brightgreen', +}) + +t.create('unknown package') + .get('/rating/npm-api-does-not-have-this-package.json') + .expectBadge({ + label: 'Rating', + message: 'package not found or too new', + color: 'red', + })