Validate response json in [apm appveyor cdnjs clojars gem] (#1883)
* split gem service into multiple files * add validation to apm, appveyor, cdnjs, clojars & gem services * fix the apm examples
This commit is contained in:
@@ -5,11 +5,22 @@ const { BaseJsonService } = require('../base')
|
||||
const { InvalidResponse } = require('../errors')
|
||||
const { version: versionColor } = require('../../lib/color-formatters')
|
||||
const { metric, addv } = require('../../lib/text-formatters')
|
||||
const { nonNegativeInteger } = require('../validators.js')
|
||||
|
||||
const apmSchema = Joi.object({
|
||||
downloads: nonNegativeInteger,
|
||||
releases: Joi.object({
|
||||
latest: Joi.string().required(),
|
||||
}),
|
||||
metadata: Joi.object({
|
||||
license: Joi.string().required(),
|
||||
}),
|
||||
})
|
||||
|
||||
class BaseAPMService extends BaseJsonService {
|
||||
async fetch(repo) {
|
||||
return this._requestJson({
|
||||
schema: Joi.object(),
|
||||
schema: apmSchema,
|
||||
url: `https://atom.io/api/packages/${repo}`,
|
||||
notFoundMessage: 'package not found',
|
||||
})
|
||||
@@ -18,6 +29,15 @@ class BaseAPMService extends BaseJsonService {
|
||||
static get defaultBadgeData() {
|
||||
return { label: 'apm' }
|
||||
}
|
||||
|
||||
static get examples() {
|
||||
return [
|
||||
{
|
||||
previewUrl: 'vim-mode',
|
||||
keywords: ['atom'],
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
class APMDownloads extends BaseAPMService {
|
||||
@@ -43,15 +63,6 @@ class APMDownloads extends BaseAPMService {
|
||||
capture: ['repo'],
|
||||
}
|
||||
}
|
||||
|
||||
static get examples() {
|
||||
return [
|
||||
{
|
||||
previewUrl: 'dm/vim-mode',
|
||||
keywords: ['atom'],
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
class APMVersion extends BaseAPMService {
|
||||
@@ -77,15 +88,6 @@ class APMVersion extends BaseAPMService {
|
||||
capture: ['repo'],
|
||||
}
|
||||
}
|
||||
|
||||
static get examples() {
|
||||
return [
|
||||
{
|
||||
previewUrl: 'v/vim-mode',
|
||||
keywords: ['atom'],
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
class APMLicense extends BaseAPMService {
|
||||
@@ -115,15 +117,6 @@ class APMLicense extends BaseAPMService {
|
||||
capture: ['repo'],
|
||||
}
|
||||
}
|
||||
|
||||
static get examples() {
|
||||
return [
|
||||
{
|
||||
previewUrl: 'l/vim-mode',
|
||||
keywords: ['atom'],
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
const Joi = require('joi')
|
||||
const { BaseJsonService } = require('../base')
|
||||
|
||||
const appVeyorSchema = Joi.object({
|
||||
build: Joi.object({
|
||||
status: Joi.string().required(),
|
||||
}),
|
||||
}).required()
|
||||
|
||||
module.exports = class AppVeyor extends BaseJsonService {
|
||||
async handle({ repo, branch }) {
|
||||
let url = `https://ci.appveyor.com/api/projects/${repo}`
|
||||
@@ -12,7 +18,7 @@ module.exports = class AppVeyor extends BaseJsonService {
|
||||
const {
|
||||
build: { status },
|
||||
} = await this._requestJson({
|
||||
schema: Joi.object(),
|
||||
schema: appVeyorSchema,
|
||||
url,
|
||||
notFoundMessage: 'project not found or access denied',
|
||||
})
|
||||
|
||||
@@ -6,12 +6,17 @@ const { NotFound } = require('../errors')
|
||||
const { addv: versionText } = require('../../lib/text-formatters')
|
||||
const { version: versionColor } = require('../../lib/color-formatters')
|
||||
|
||||
const cdnjsSchema = Joi.object({
|
||||
// optional due to non-standard 'not found' condition
|
||||
version: Joi.string(),
|
||||
}).required()
|
||||
|
||||
module.exports = class Cdnjs extends BaseJsonService {
|
||||
async handle({ library }) {
|
||||
const url = `https://api.cdnjs.com/libraries/${library}?fields=version`
|
||||
const json = await this._requestJson({
|
||||
url,
|
||||
schema: Joi.any(),
|
||||
schema: cdnjsSchema,
|
||||
})
|
||||
|
||||
if (Object.keys(json).length === 0) {
|
||||
@@ -19,11 +24,10 @@ module.exports = class Cdnjs extends BaseJsonService {
|
||||
status code = 200, body = {} */
|
||||
throw new NotFound()
|
||||
}
|
||||
const version = json.version || 0
|
||||
|
||||
return {
|
||||
message: versionText(version),
|
||||
color: versionColor(version),
|
||||
message: versionText(json.version),
|
||||
color: versionColor(json.version),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,12 +5,17 @@ const { BaseJsonService } = require('../base')
|
||||
const { NotFound } = require('../errors')
|
||||
const { version: versionColor } = require('../../lib/color-formatters')
|
||||
|
||||
const clojarsSchema = Joi.object({
|
||||
// optional due to non-standard 'not found' condition
|
||||
version: Joi.string(),
|
||||
}).required()
|
||||
|
||||
module.exports = class Clojars extends BaseJsonService {
|
||||
async handle({ clojar }) {
|
||||
const url = `https://clojars.org/${clojar}/latest-version.json`
|
||||
const json = await this._requestJson({
|
||||
url,
|
||||
schema: Joi.any(),
|
||||
schema: clojarsSchema,
|
||||
})
|
||||
|
||||
if (Object.keys(json).length === 0) {
|
||||
|
||||
149
services/gem/gem-downloads.service.js
Normal file
149
services/gem/gem-downloads.service.js
Normal file
@@ -0,0 +1,149 @@
|
||||
'use strict'
|
||||
|
||||
const semver = require('semver')
|
||||
const Joi = require('joi')
|
||||
|
||||
const { BaseJsonService } = require('../base')
|
||||
const { InvalidResponse } = require('../errors')
|
||||
const {
|
||||
downloadCount: downloadCountColor,
|
||||
} = require('../../lib/color-formatters')
|
||||
const { metric } = require('../../lib/text-formatters')
|
||||
const { latest: latestVersion } = require('../../lib/version')
|
||||
const { nonNegativeInteger } = require('../validators.js')
|
||||
|
||||
const gemsSchema = Joi.object({
|
||||
downloads: nonNegativeInteger,
|
||||
version_downloads: nonNegativeInteger,
|
||||
}).required()
|
||||
|
||||
const versionsSchema = Joi.array()
|
||||
.items(
|
||||
Joi.object({
|
||||
prerelease: Joi.boolean().required(),
|
||||
number: Joi.string().required(),
|
||||
downloads_count: nonNegativeInteger,
|
||||
})
|
||||
)
|
||||
.min(1)
|
||||
.required()
|
||||
|
||||
module.exports = class GemDownloads extends BaseJsonService {
|
||||
async fetch(repo, info) {
|
||||
const endpoint = info === 'dv' ? 'versions/' : 'gems/'
|
||||
const schema = info === 'dv' ? versionsSchema : gemsSchema
|
||||
const url = `https://rubygems.org/api/v1/${endpoint}${repo}.json`
|
||||
return this._requestJson({
|
||||
url,
|
||||
schema,
|
||||
})
|
||||
}
|
||||
|
||||
_getLabel(version, info) {
|
||||
if (version) {
|
||||
return 'downloads@' + version
|
||||
} else {
|
||||
if (info === 'dtv') {
|
||||
return 'downloads@latest'
|
||||
} else {
|
||||
return 'downloads'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async handle({ info, rubygem }) {
|
||||
const splitRubygem = rubygem.split('/')
|
||||
const repo = splitRubygem[0]
|
||||
let version =
|
||||
splitRubygem.length > 1 ? splitRubygem[splitRubygem.length - 1] : null
|
||||
version = version === 'stable' ? version : semver.valid(version)
|
||||
const label = this._getLabel(version, info)
|
||||
const json = await this.fetch(repo, info)
|
||||
|
||||
let downloads
|
||||
if (info === 'dt') {
|
||||
downloads = metric(json.downloads)
|
||||
} else if (info === 'dtv') {
|
||||
downloads = metric(json.version_downloads)
|
||||
} else if (info === 'dv') {
|
||||
let versionData
|
||||
if (version !== null && version === 'stable') {
|
||||
const versions = json
|
||||
.filter(function(ver) {
|
||||
return ver.prerelease === false
|
||||
})
|
||||
.map(function(ver) {
|
||||
return ver.number
|
||||
})
|
||||
// Found latest stable version.
|
||||
const stableVersion = latestVersion(versions)
|
||||
versionData = json.filter(function(ver) {
|
||||
return ver.number === stableVersion
|
||||
})[0]
|
||||
downloads = metric(versionData.downloads_count)
|
||||
} else if (version !== null) {
|
||||
versionData = json.filter(function(ver) {
|
||||
return ver.number === version
|
||||
})[0]
|
||||
|
||||
downloads = metric(versionData.downloads_count)
|
||||
} else {
|
||||
throw new InvalidResponse({
|
||||
underlyingError: new Error('version is null'),
|
||||
})
|
||||
}
|
||||
} else {
|
||||
throw new InvalidResponse({
|
||||
underlyingError: new Error('info is invalid'),
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
label: label,
|
||||
message: downloads,
|
||||
color: downloadCountColor(downloads),
|
||||
}
|
||||
}
|
||||
|
||||
// Metadata
|
||||
static get defaultBadgeData() {
|
||||
return { label: 'downloads' }
|
||||
}
|
||||
|
||||
static get category() {
|
||||
return 'downloads'
|
||||
}
|
||||
|
||||
static get url() {
|
||||
return {
|
||||
base: 'gem',
|
||||
format: '(dt|dtv|dv)/(.+)',
|
||||
capture: ['info', 'rubygem'],
|
||||
}
|
||||
}
|
||||
|
||||
static get examples() {
|
||||
return [
|
||||
{
|
||||
title: 'Gem',
|
||||
previewUrl: 'dv/rails/stable',
|
||||
keywords: ['ruby'],
|
||||
},
|
||||
{
|
||||
title: 'Gem',
|
||||
previewUrl: 'dv/rails/4.1.0',
|
||||
keywords: ['ruby'],
|
||||
},
|
||||
{
|
||||
title: 'Gem',
|
||||
previewUrl: 'dtv/rails',
|
||||
keywords: ['ruby'],
|
||||
},
|
||||
{
|
||||
title: 'Gem',
|
||||
previewUrl: 'dt/rails',
|
||||
keywords: ['ruby'],
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
51
services/gem/gem-owner.service.js
Normal file
51
services/gem/gem-owner.service.js
Normal file
@@ -0,0 +1,51 @@
|
||||
'use strict'
|
||||
|
||||
const Joi = require('joi')
|
||||
|
||||
const { BaseJsonService } = require('../base')
|
||||
const { floorCount: floorCountColor } = require('../../lib/color-formatters')
|
||||
|
||||
const ownerSchema = Joi.array().required()
|
||||
|
||||
module.exports = class GemOwner extends BaseJsonService {
|
||||
async handle({ user }) {
|
||||
const url = `https://rubygems.org/api/v1/owners/${user}/gems.json`
|
||||
const json = await this._requestJson({
|
||||
url,
|
||||
schema: ownerSchema,
|
||||
})
|
||||
const count = json.length
|
||||
|
||||
return {
|
||||
message: count,
|
||||
color: floorCountColor(count, 10, 50, 100),
|
||||
}
|
||||
}
|
||||
|
||||
// Metadata
|
||||
static get defaultBadgeData() {
|
||||
return { label: 'gems' }
|
||||
}
|
||||
|
||||
static get category() {
|
||||
return 'other'
|
||||
}
|
||||
|
||||
static get url() {
|
||||
return {
|
||||
base: 'gem/u',
|
||||
format: '(.+)',
|
||||
capture: ['user'],
|
||||
}
|
||||
}
|
||||
|
||||
static get examples() {
|
||||
return [
|
||||
{
|
||||
title: 'Gems',
|
||||
previewUrl: 'raphink',
|
||||
keywords: ['ruby'],
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
95
services/gem/gem-rank.service.js
Normal file
95
services/gem/gem-rank.service.js
Normal file
@@ -0,0 +1,95 @@
|
||||
'use strict'
|
||||
|
||||
const Joi = require('joi')
|
||||
|
||||
const { BaseJsonService } = require('../base')
|
||||
const { floorCount: floorCountColor } = require('../../lib/color-formatters')
|
||||
const { ordinalNumber } = require('../../lib/text-formatters')
|
||||
const { nonNegativeInteger } = require('../validators.js')
|
||||
|
||||
const totalSchema = Joi.array()
|
||||
.items(
|
||||
Joi.object({
|
||||
total_ranking: nonNegativeInteger,
|
||||
})
|
||||
)
|
||||
.min(1)
|
||||
.required()
|
||||
const dailySchema = Joi.array()
|
||||
.items(
|
||||
Joi.object({
|
||||
daily_ranking: nonNegativeInteger,
|
||||
})
|
||||
)
|
||||
.min(1)
|
||||
.required()
|
||||
|
||||
module.exports = class GemRank extends BaseJsonService {
|
||||
_getApiUrl(repo, totalRank, dailyRank) {
|
||||
let endpoint
|
||||
if (totalRank) {
|
||||
endpoint = '/total_ranking.json'
|
||||
} else if (dailyRank) {
|
||||
endpoint = '/daily_ranking.json'
|
||||
}
|
||||
return `http://bestgems.org/api/v1/gems/${repo}${endpoint}`
|
||||
}
|
||||
|
||||
async handle({ info, repo }) {
|
||||
const totalRank = info === 'rt'
|
||||
const dailyRank = info === 'rd'
|
||||
const schema = totalRank ? totalSchema : dailySchema
|
||||
const url = this._getApiUrl(repo, totalRank, dailyRank)
|
||||
const json = await this._requestJson({
|
||||
url,
|
||||
schema,
|
||||
})
|
||||
|
||||
let rank
|
||||
if (totalRank) {
|
||||
rank = json[0].total_ranking
|
||||
} else if (dailyRank) {
|
||||
rank = json[0].daily_ranking
|
||||
}
|
||||
const count = Math.floor(100000 / rank)
|
||||
let message = ordinalNumber(rank)
|
||||
message += totalRank ? '' : ' daily'
|
||||
|
||||
return {
|
||||
message: message,
|
||||
color: floorCountColor(count, 10, 50, 100),
|
||||
}
|
||||
}
|
||||
|
||||
// Metadata
|
||||
static get defaultBadgeData() {
|
||||
return { label: 'rank' }
|
||||
}
|
||||
|
||||
static get category() {
|
||||
return 'rating'
|
||||
}
|
||||
|
||||
static get url() {
|
||||
return {
|
||||
base: 'gem',
|
||||
format: '(rt|rd)/(.+)',
|
||||
capture: ['info', 'repo'],
|
||||
}
|
||||
}
|
||||
|
||||
static get examples() {
|
||||
return [
|
||||
{
|
||||
title: 'Gems',
|
||||
previewUrl: 'rt/puppet',
|
||||
keywords: ['ruby'],
|
||||
},
|
||||
{
|
||||
title: 'Gems',
|
||||
previewUrl: 'rd/facter',
|
||||
keywords: ['ruby'],
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
55
services/gem/gem-version.service.js
Normal file
55
services/gem/gem-version.service.js
Normal file
@@ -0,0 +1,55 @@
|
||||
'use strict'
|
||||
|
||||
const Joi = require('joi')
|
||||
|
||||
const { BaseJsonService } = require('../base')
|
||||
const { addv: versionText } = require('../../lib/text-formatters')
|
||||
const { version: versionColor } = require('../../lib/color-formatters')
|
||||
|
||||
// Response should contain a string key 'version'
|
||||
// In most cases this will be a SemVer
|
||||
// but the registry doesn't actually enforce this
|
||||
const versionSchema = Joi.object({
|
||||
version: Joi.string().required(),
|
||||
}).required()
|
||||
|
||||
module.exports = class GemVersion extends BaseJsonService {
|
||||
async handle({ repo }) {
|
||||
const url = `https://rubygems.org/api/v1/gems/${repo}.json`
|
||||
const { version } = await this._requestJson({
|
||||
url,
|
||||
schema: versionSchema,
|
||||
})
|
||||
return {
|
||||
message: versionText(version),
|
||||
color: versionColor(version),
|
||||
}
|
||||
}
|
||||
|
||||
// Metadata
|
||||
static get defaultBadgeData() {
|
||||
return { label: 'gem' }
|
||||
}
|
||||
|
||||
static get category() {
|
||||
return 'version'
|
||||
}
|
||||
|
||||
static get url() {
|
||||
return {
|
||||
base: 'gem/v',
|
||||
format: '(.+)',
|
||||
capture: ['repo'],
|
||||
}
|
||||
}
|
||||
|
||||
static get examples() {
|
||||
return [
|
||||
{
|
||||
title: 'Gem',
|
||||
previewUrl: 'formatador',
|
||||
keywords: ['ruby'],
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,294 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const semver = require('semver')
|
||||
const Joi = require('joi')
|
||||
|
||||
const { BaseJsonService } = require('../base')
|
||||
const { InvalidResponse } = require('../errors')
|
||||
const { addv: versionText } = require('../../lib/text-formatters')
|
||||
const { version: versionColor } = require('../../lib/color-formatters')
|
||||
const {
|
||||
floorCount: floorCountColor,
|
||||
downloadCount: downloadCountColor,
|
||||
} = require('../../lib/color-formatters')
|
||||
const { metric, ordinalNumber } = require('../../lib/text-formatters')
|
||||
const { latest: latestVersion } = require('../../lib/version')
|
||||
|
||||
class GemVersion extends BaseJsonService {
|
||||
async handle({ repo }) {
|
||||
const url = `https://rubygems.org/api/v1/gems/${repo}.json`
|
||||
const { version } = await this._requestJson({
|
||||
url,
|
||||
schema: Joi.object(),
|
||||
})
|
||||
return {
|
||||
message: versionText(version),
|
||||
color: versionColor(version),
|
||||
}
|
||||
}
|
||||
|
||||
// Metadata
|
||||
static get defaultBadgeData() {
|
||||
return { label: 'gem' }
|
||||
}
|
||||
|
||||
static get category() {
|
||||
return 'version'
|
||||
}
|
||||
|
||||
static get url() {
|
||||
return {
|
||||
base: 'gem/v',
|
||||
format: '(.+)',
|
||||
capture: ['repo'],
|
||||
}
|
||||
}
|
||||
|
||||
static get examples() {
|
||||
return [
|
||||
{
|
||||
title: 'Gem',
|
||||
previewUrl: 'formatador',
|
||||
keywords: ['ruby'],
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
class GemDownloads extends BaseJsonService {
|
||||
fetch(repo, info) {
|
||||
const endpoint = info === 'dv' ? 'versions/' : 'gems/'
|
||||
const url = `https://rubygems.org/api/v1/${endpoint}${repo}.json`
|
||||
return this._requestJson({
|
||||
url,
|
||||
schema: Joi.any(),
|
||||
})
|
||||
}
|
||||
|
||||
_getLabel(version, info) {
|
||||
if (version) {
|
||||
return 'downloads@' + version
|
||||
} else {
|
||||
if (info === 'dtv') {
|
||||
return 'downloads@latest'
|
||||
} else {
|
||||
return 'downloads'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async handle({ info, rubygem }) {
|
||||
const splitRubygem = rubygem.split('/')
|
||||
const repo = splitRubygem[0]
|
||||
let version =
|
||||
splitRubygem.length > 1 ? splitRubygem[splitRubygem.length - 1] : null
|
||||
version = version === 'stable' ? version : semver.valid(version)
|
||||
const label = this._getLabel(version, info)
|
||||
const json = await this.fetch(repo, info)
|
||||
|
||||
let downloads
|
||||
if (info === 'dt') {
|
||||
downloads = metric(json.downloads)
|
||||
} else if (info === 'dtv') {
|
||||
downloads = metric(json.version_downloads)
|
||||
} else if (info === 'dv') {
|
||||
let versionData
|
||||
if (version !== null && version === 'stable') {
|
||||
const versions = json
|
||||
.filter(function(ver) {
|
||||
return ver.prerelease === false
|
||||
})
|
||||
.map(function(ver) {
|
||||
return ver.number
|
||||
})
|
||||
// Found latest stable version.
|
||||
const stableVersion = latestVersion(versions)
|
||||
versionData = json.filter(function(ver) {
|
||||
return ver.number === stableVersion
|
||||
})[0]
|
||||
downloads = metric(versionData.downloads_count)
|
||||
} else if (version !== null) {
|
||||
versionData = json.filter(function(ver) {
|
||||
return ver.number === version
|
||||
})[0]
|
||||
|
||||
downloads = metric(versionData.downloads_count)
|
||||
} else {
|
||||
throw new InvalidResponse({
|
||||
underlyingError: new Error('version is null'),
|
||||
})
|
||||
}
|
||||
} else {
|
||||
throw new InvalidResponse({
|
||||
underlyingError: new Error('info is invalid'),
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
label: label,
|
||||
message: downloads,
|
||||
color: downloadCountColor(downloads),
|
||||
}
|
||||
}
|
||||
|
||||
// Metadata
|
||||
static get defaultBadgeData() {
|
||||
return { label: 'downloads' }
|
||||
}
|
||||
|
||||
static get category() {
|
||||
return 'downloads'
|
||||
}
|
||||
|
||||
static get url() {
|
||||
return {
|
||||
base: 'gem',
|
||||
format: '(dt|dtv|dv)/(.+)',
|
||||
capture: ['info', 'rubygem'],
|
||||
}
|
||||
}
|
||||
|
||||
static get examples() {
|
||||
return [
|
||||
{
|
||||
title: 'Gem',
|
||||
previewUrl: 'dv/rails/stable',
|
||||
keywords: ['ruby'],
|
||||
},
|
||||
{
|
||||
title: 'Gem',
|
||||
previewUrl: 'dv/rails/4.1.0',
|
||||
keywords: ['ruby'],
|
||||
},
|
||||
{
|
||||
title: 'Gem',
|
||||
previewUrl: 'dtv/rails',
|
||||
keywords: ['ruby'],
|
||||
},
|
||||
{
|
||||
title: 'Gem',
|
||||
previewUrl: 'dt/rails',
|
||||
keywords: ['ruby'],
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
class GemOwner extends BaseJsonService {
|
||||
async handle({ user }) {
|
||||
const url = `https://rubygems.org/api/v1/owners/${user}/gems.json`
|
||||
const json = await this._requestJson({
|
||||
url,
|
||||
schema: Joi.array(),
|
||||
})
|
||||
const count = json.length
|
||||
|
||||
return {
|
||||
message: count,
|
||||
color: floorCountColor(count, 10, 50, 100),
|
||||
}
|
||||
}
|
||||
|
||||
// Metadata
|
||||
static get defaultBadgeData() {
|
||||
return { label: 'gems' }
|
||||
}
|
||||
|
||||
static get category() {
|
||||
return 'other'
|
||||
}
|
||||
|
||||
static get url() {
|
||||
return {
|
||||
base: 'gem/u',
|
||||
format: '(.+)',
|
||||
capture: ['user'],
|
||||
}
|
||||
}
|
||||
|
||||
static get examples() {
|
||||
return [
|
||||
{
|
||||
title: 'Gems',
|
||||
previewUrl: 'raphink',
|
||||
keywords: ['ruby'],
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
class GemRank extends BaseJsonService {
|
||||
_getApiUrl(repo, totalRank, dailyRank) {
|
||||
let endpoint
|
||||
if (totalRank) {
|
||||
endpoint = '/total_ranking.json'
|
||||
} else if (dailyRank) {
|
||||
endpoint = '/daily_ranking.json'
|
||||
}
|
||||
return `http://bestgems.org/api/v1/gems/${repo}${endpoint}`
|
||||
}
|
||||
|
||||
async handle({ info, repo }) {
|
||||
const totalRank = info === 'rt'
|
||||
const dailyRank = info === 'rd'
|
||||
const url = this._getApiUrl(repo, totalRank, dailyRank)
|
||||
const json = await this._requestJson({
|
||||
url,
|
||||
schema: Joi.array(),
|
||||
})
|
||||
|
||||
let rank
|
||||
if (totalRank) {
|
||||
rank = json[0].total_ranking
|
||||
} else if (dailyRank) {
|
||||
rank = json[0].daily_ranking
|
||||
}
|
||||
const count = Math.floor(100000 / rank)
|
||||
let message = ordinalNumber(rank)
|
||||
message += totalRank ? '' : ' daily'
|
||||
|
||||
return {
|
||||
message: message,
|
||||
color: floorCountColor(count, 10, 50, 100),
|
||||
}
|
||||
}
|
||||
|
||||
// Metadata
|
||||
static get defaultBadgeData() {
|
||||
return { label: 'rank' }
|
||||
}
|
||||
|
||||
static get category() {
|
||||
return 'rating'
|
||||
}
|
||||
|
||||
static get url() {
|
||||
return {
|
||||
base: 'gem',
|
||||
format: '(rt|rd)/(.+)',
|
||||
capture: ['info', 'repo'],
|
||||
}
|
||||
}
|
||||
|
||||
static get examples() {
|
||||
return [
|
||||
{
|
||||
title: 'Gems',
|
||||
previewUrl: 'rt/puppet',
|
||||
keywords: ['ruby'],
|
||||
},
|
||||
{
|
||||
title: 'Gems',
|
||||
previewUrl: 'rd/facter',
|
||||
keywords: ['ruby'],
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
GemVersion,
|
||||
GemDownloads,
|
||||
GemOwner,
|
||||
GemRank,
|
||||
}
|
||||
@@ -3,13 +3,11 @@
|
||||
const Joi = require('joi')
|
||||
const { BaseJsonService } = require('../base')
|
||||
const { metric } = require('../../lib/text-formatters')
|
||||
const { nonNegativeInteger } = require('../validators.js')
|
||||
|
||||
// https://github.com/npm/registry/blob/master/docs/download-counts.md#output
|
||||
const pointResponseSchema = Joi.object({
|
||||
downloads: Joi.number()
|
||||
.integer()
|
||||
.min(0)
|
||||
.required(),
|
||||
downloads: nonNegativeInteger,
|
||||
}).required()
|
||||
|
||||
// https://github.com/npm/registry/blob/master/docs/download-counts.md#output-1
|
||||
|
||||
12
services/validators.js
Normal file
12
services/validators.js
Normal file
@@ -0,0 +1,12 @@
|
||||
'use strict'
|
||||
|
||||
const Joi = require('joi')
|
||||
|
||||
const nonNegativeInteger = Joi.number()
|
||||
.integer()
|
||||
.min(0)
|
||||
.required()
|
||||
|
||||
module.exports = {
|
||||
nonNegativeInteger,
|
||||
}
|
||||
Reference in New Issue
Block a user