Unify order of properties and methods in services (#3353)

I find having these in a consistent order makes the services much faster to read.

This is the order I’ve generally been using:

1. Category
2. Route
3. Examples
4. Rendering
5. Other helpers (`fetch()`, `transform()`)
6. `handle()`
This commit is contained in:
Paul Melnikow
2019-04-23 21:36:04 -04:00
committed by GitHub
parent 12191e20c4
commit 1cdcaabd38
48 changed files with 769 additions and 740 deletions

View File

@@ -12,15 +12,40 @@ parserOptions:
sourceType: 'script'
overrides:
files:
- gatsby-browser.js
parserOptions:
sourceType: 'module'
- files:
- gatsby-browser.js
parserOptions:
sourceType: 'module'
- files:
- 'core/base-service/**/*.js'
- 'services/**/*.js'
rules:
sort-class-members/sort-class-members:
[
'warn',
{
order:
[
'name',
'category',
'isDeprecated',
'route',
'examples',
'defaultBadgeData',
'render',
'constructor',
'fetch',
'transform',
'handle',
],
},
]
plugins:
- mocha
- no-extension-in-require
- 'chai-friendly'
- chai-friendly
- sort-class-members
rules:
# Disable some rules from eslint:recommended.

View File

@@ -70,26 +70,6 @@ const serviceDataSchema = Joi.object({
.required()
module.exports = class BaseService {
constructor({ sendAndCacheRequest }, { handleInternalErrors }) {
this._requestFetcher = sendAndCacheRequest
this._handleInternalErrors = handleInternalErrors
}
static render(props) {
throw new Error(`render() function not implemented for ${this.name}`)
}
/**
* Asynchronous function to handle requests for this service. Take the route
* parameters (as defined in the `route` property), perform a request using
* `this._sendAndCacheRequest`, and return the badge data.
*/
async handle(namedParams, queryParams) {
throw new Error(`Handler not implemented for ${this.constructor.name}`)
}
// Metadata
/**
* Name of the category to sort this badge into (eg. "build"). Used to sort
* the badges on the main shields.io website.
@@ -98,6 +78,10 @@ module.exports = class BaseService {
throw new Error(`Category not set for ${this.name}`)
}
static get isDeprecated() {
return false
}
/**
* Returns an object:
* - base: (Optional) The base path of the routes for this service. This is
@@ -127,17 +111,14 @@ module.exports = class BaseService {
throw new Error(`Route not defined for ${this.name}`)
}
static get isDeprecated() {
return false
}
/**
* Default data for the badge. Can include label, logo, and color. These
* defaults are used if the value is neither included in the service data
* from the handler nor overridden by the user via query parameters.
*/
static get defaultBadgeData() {
return {}
static get _cacheLength() {
const cacheLengths = {
build: 30,
license: 3600,
version: 300,
debug: 60,
}
return cacheLengths[this.category]
}
/**
@@ -172,6 +153,15 @@ module.exports = class BaseService {
return []
}
/**
* Default data for the badge. Can include label, logo, and color. These
* defaults are used if the value is neither included in the service data
* from the handler nor overridden by the user via query parameters.
*/
static get defaultBadgeData() {
return {}
}
static validateDefinition() {
assertValidCategory(this.category, `Category for ${this.name}`)
@@ -219,14 +209,53 @@ module.exports = class BaseService {
return result
}
static get _cacheLength() {
const cacheLengths = {
build: 30,
license: 3600,
version: 300,
debug: 60,
}
return cacheLengths[this.category]
static render(props) {
throw new Error(`render() function not implemented for ${this.name}`)
}
constructor({ sendAndCacheRequest }, { handleInternalErrors }) {
this._requestFetcher = sendAndCacheRequest
this._handleInternalErrors = handleInternalErrors
}
async _request({ url, options = {}, errorMessages = {} }) {
const logTrace = (...args) => trace.logTrace('fetch', ...args)
logTrace(emojic.bowAndArrow, 'Request', url, '\n', options)
const { res, buffer } = await this._requestFetcher(url, options)
logTrace(emojic.dart, 'Response status code', res.statusCode)
return checkErrorResponse.asPromise(errorMessages)({ buffer, res })
}
static _validate(
data,
schema,
{
prettyErrorMessage = 'invalid response data',
includeKeys = false,
allowAndStripUnknownKeys = true,
} = {}
) {
return validate(
{
ErrorClass: InvalidResponse,
prettyErrorMessage,
includeKeys,
traceErrorMessage: 'Response did not match schema',
traceSuccessMessage: 'Response after validation',
allowAndStripUnknownKeys,
},
data,
schema
)
}
/**
* Asynchronous function to handle requests for this service. Take the route
* parameters (as defined in the `route` property), perform a request using
* `this._sendAndCacheRequest`, and return the badge data.
*/
async handle(namedParams, queryParams) {
throw new Error(`Handler not implemented for ${this.constructor.name}`)
}
_handleError(error) {
@@ -398,35 +427,4 @@ module.exports = class BaseService {
})
)
}
static _validate(
data,
schema,
{
prettyErrorMessage = 'invalid response data',
includeKeys = false,
allowAndStripUnknownKeys = true,
} = {}
) {
return validate(
{
ErrorClass: InvalidResponse,
prettyErrorMessage,
includeKeys,
traceErrorMessage: 'Response did not match schema',
traceSuccessMessage: 'Response after validation',
allowAndStripUnknownKeys,
},
data,
schema
)
}
async _request({ url, options = {}, errorMessages = {} }) {
const logTrace = (...args) => trace.logTrace('fetch', ...args)
logTrace(emojic.bowAndArrow, 'Request', url, '\n', options)
const { res, buffer } = await this._requestFetcher(url, options)
logTrace(emojic.dart, 'Response status code', res.statusCode)
return checkErrorResponse.asPromise(errorMessages)({ buffer, res })
}
}

View File

@@ -25,22 +25,16 @@ const queryParamSchema = Joi.object({
.required()
class DummyService extends BaseService {
static render({ namedParamA, queryParamA }) {
return {
message: `Hello namedParamA: ${namedParamA} with queryParamA: ${queryParamA}`,
}
}
async handle({ namedParamA }, { queryParamA }) {
return this.constructor.render({ namedParamA, queryParamA })
}
static get category() {
return 'other'
}
static get defaultBadgeData() {
return { label: 'cat', namedLogo: 'appveyor' }
static get route() {
return {
base: 'foo',
pattern: ':namedParamA',
queryParamSchema,
}
}
static get examples() {
@@ -54,13 +48,19 @@ class DummyService extends BaseService {
]
}
static get route() {
static get defaultBadgeData() {
return { label: 'cat', namedLogo: 'appveyor' }
}
static render({ namedParamA, queryParamA }) {
return {
base: 'foo',
pattern: ':namedParamA',
queryParamSchema,
message: `Hello namedParamA: ${namedParamA} with queryParamA: ${queryParamA}`,
}
}
async handle({ namedParamA }, { queryParamA }) {
return this.constructor.render({ namedParamA, queryParamA })
}
}
describe('BaseService', function() {

View File

@@ -38,22 +38,22 @@ function deprecatedService(attrs) {
return category
}
static get route() {
return route
}
static get isDeprecated() {
return true
}
static get defaultBadgeData() {
return { label }
static get route() {
return route
}
static get examples() {
return examples
}
static get defaultBadgeData() {
return { label }
}
async handle() {
throw new Deprecated({ prettyMessage: message })
}

View File

@@ -40,18 +40,6 @@ module.exports = function redirector(attrs) {
} = Joi.attempt(attrs, attrSchema, `Redirector for ${attrs.route.base}`)
return class Redirector extends BaseService {
static get category() {
return category
}
static get route() {
return route
}
static get isDeprecated() {
return true
}
static get name() {
if (name) {
return name
@@ -62,6 +50,18 @@ module.exports = function redirector(attrs) {
}
}
static get category() {
return category
}
static get isDeprecated() {
return true
}
static get route() {
return route
}
static register({ camp, requestCounter }) {
const { regex, captureNames } = prepareRoute(this.route)

6
package-lock.json generated
View File

@@ -8977,6 +8977,12 @@
"integrity": "sha512-lHBVRIaz5ibnIgNG07JNiAuBUeKhEf8l4etNx5vfAEwqQ5tcuK3jV9yjmopPgQDagQb7HwIuQVsE3IVcGrRnag==",
"dev": true
},
"eslint-plugin-sort-class-members": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-sort-class-members/-/eslint-plugin-sort-class-members-1.4.0.tgz",
"integrity": "sha512-FQG6d4Cy2vYmG9gr6J138E91WaltqwOk/b/7GCssPqnUmizrcgOeN91bV5eOTuoS4RSH1Jdn4ukWEtyWLwV8ig==",
"dev": true
},
"eslint-plugin-standard": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-4.0.0.tgz",

View File

@@ -164,6 +164,7 @@
"eslint-plugin-promise": "^4.1.1",
"eslint-plugin-react": "^7.12.4",
"eslint-plugin-react-hooks": "^1.6.0",
"eslint-plugin-sort-class-members": "^1.4.0",
"eslint-plugin-standard": "^4.0.0",
"fetch-ponyfill": "^6.0.0",
"fs-readfile-promise": "^3.0.1",

View File

@@ -18,16 +18,16 @@ const schema = Joi.object({
}).required()
class BaseAmoService extends BaseJsonService {
static get defaultBadgeData() {
return { label: 'mozilla add-on' }
}
async fetch({ addonId }) {
return this._requestJson({
schema,
url: `https://addons.mozilla.org/api/v3/addons/addon/${addonId}`,
})
}
static get defaultBadgeData() {
return { label: 'mozilla add-on' }
}
}
module.exports = { BaseAmoService, keywords }

View File

@@ -19,14 +19,14 @@ const condaSchema = Joi.object({
}).required()
module.exports = class BaseCondaService extends BaseJsonService {
static get defaultBadgeData() {
return { label: 'conda' }
}
async fetch({ channel, pkg }) {
return this._requestJson({
schema: condaSchema,
url: `https://api.anaconda.org/package/${channel}/${pkg}`,
})
}
static get defaultBadgeData() {
return { label: 'conda' }
}
}

View File

@@ -33,12 +33,6 @@ class PowershellGalleryPlatformSupport extends BaseXmlService {
return 'platform-support'
}
static get defaultBadgeData() {
return {
label: 'platform',
}
}
static get route() {
return {
base: 'powershellgallery/p',
@@ -58,6 +52,12 @@ class PowershellGalleryPlatformSupport extends BaseXmlService {
]
}
static get defaultBadgeData() {
return {
label: 'platform',
}
}
static render({ platforms }) {
return {
message: platforms.join(' | '),

View File

@@ -22,10 +22,6 @@ module.exports = class PubVersion extends BaseJsonService {
}
}
static get defaultBadgeData() {
return { label: 'pub' }
}
static get examples() {
return [
{
@@ -45,6 +41,10 @@ module.exports = class PubVersion extends BaseJsonService {
]
}
static get defaultBadgeData() {
return { label: 'pub' }
}
async fetch({ packageName }) {
return this._requestJson({
schema,

View File

@@ -15,10 +15,6 @@ module.exports = class PuppetforgeModuleVersion extends BasePuppetForgeModulesSe
}
}
static get defaultBadgeData() {
return { label: 'puppetforge' }
}
static get examples() {
return [
{
@@ -32,6 +28,10 @@ module.exports = class PuppetforgeModuleVersion extends BasePuppetForgeModulesSe
]
}
static get defaultBadgeData() {
return { label: 'puppetforge' }
}
async handle({ user, moduleName }) {
const data = await this.fetch({ user, moduleName })
return renderVersionBadge({ version: data.current_release.version })

View File

@@ -9,10 +9,6 @@ module.exports = class PuppetForgeModuleCountService extends BasePuppetForgeUser
return 'other'
}
static get defaultBadgeData() {
return { label: 'modules' }
}
static get route() {
return {
base: 'puppetforge/mc',
@@ -32,9 +28,8 @@ module.exports = class PuppetForgeModuleCountService extends BasePuppetForgeUser
]
}
async handle({ user }) {
const data = await this.fetch({ user })
return this.constructor.render({ modules: data.module_count })
static get defaultBadgeData() {
return { label: 'modules' }
}
static render({ modules }) {
@@ -43,4 +38,9 @@ module.exports = class PuppetForgeModuleCountService extends BasePuppetForgeUser
color: floorCountColor(modules, 5, 10, 50),
}
}
async handle({ user }) {
const data = await this.fetch({ user })
return this.constructor.render({ modules: data.module_count })
}
}

View File

@@ -9,10 +9,6 @@ module.exports = class PuppetForgeReleaseCountService extends BasePuppetForgeUse
return 'other'
}
static get defaultBadgeData() {
return { label: 'releases' }
}
static get route() {
return {
base: 'puppetforge/rc',
@@ -32,9 +28,8 @@ module.exports = class PuppetForgeReleaseCountService extends BasePuppetForgeUse
]
}
async handle({ user }) {
const data = await this.fetch({ user })
return this.constructor.render({ releases: data.release_count })
static get defaultBadgeData() {
return { label: 'releases' }
}
static render({ releases }) {
@@ -43,4 +38,9 @@ module.exports = class PuppetForgeReleaseCountService extends BasePuppetForgeUse
color: floorCountColor(releases, 10, 50, 100),
}
}
async handle({ user }) {
const data = await this.fetch({ user })
return this.constructor.render({ releases: data.release_count })
}
}

View File

@@ -12,10 +12,6 @@ module.exports = class PypiDjangoVersions extends PypiBase {
return this.buildRoute('pypi/djversions')
}
static get defaultBadgeData() {
return { label: 'django versions' }
}
static get examples() {
return [
{
@@ -28,6 +24,10 @@ module.exports = class PypiDjangoVersions extends PypiBase {
]
}
static get defaultBadgeData() {
return { label: 'django versions' }
}
static render({ versions }) {
if (versions.length > 0) {
return {

View File

@@ -34,33 +34,6 @@ const periodMap = {
// this badge uses PyPI Stats instead of the PyPI API
// so it doesn't extend PypiBase
module.exports = class PypiDownloads extends BaseJsonService {
async fetch({ packageName }) {
return this._requestJson({
url: `https://pypistats.org/api/packages/${packageName.toLowerCase()}/recent`,
schema,
errorMessages: { 404: 'package not found' },
})
}
static render({ period, downloads }) {
return {
message: `${metric(downloads)}${periodMap[period].suffix}`,
color: downloadCount(downloads),
}
}
async handle({ period, packageName }) {
const json = await this.fetch({ packageName })
return this.constructor.render({
period,
downloads: json.data[periodMap[period].api_field],
})
}
static get defaultBadgeData() {
return { label: 'downloads' }
}
static get category() {
return 'downloads'
}
@@ -85,4 +58,31 @@ module.exports = class PypiDownloads extends BaseJsonService {
},
]
}
static get defaultBadgeData() {
return { label: 'downloads' }
}
static render({ period, downloads }) {
return {
message: `${metric(downloads)}${periodMap[period].suffix}`,
color: downloadCount(downloads),
}
}
async fetch({ packageName }) {
return this._requestJson({
url: `https://pypistats.org/api/packages/${packageName.toLowerCase()}/recent`,
schema,
errorMessages: { 404: 'package not found' },
})
}
async handle({ period, packageName }) {
const json = await this.fetch({ packageName })
return this.constructor.render({
period,
downloads: json.data[periodMap[period].api_field],
})
}
}

View File

@@ -12,10 +12,6 @@ module.exports = class PypiFormat extends PypiBase {
return this.buildRoute('pypi/format')
}
static get defaultBadgeData() {
return { label: 'format' }
}
static get examples() {
return [
{
@@ -28,6 +24,10 @@ module.exports = class PypiFormat extends PypiBase {
]
}
static get defaultBadgeData() {
return { label: 'format' }
}
static render({ hasWheel, hasEgg }) {
if (hasWheel) {
return {

View File

@@ -12,10 +12,6 @@ module.exports = class PypiImplementation extends PypiBase {
return this.buildRoute('pypi/implementation')
}
static get defaultBadgeData() {
return { label: 'implementation' }
}
static get examples() {
return [
{
@@ -28,6 +24,10 @@ module.exports = class PypiImplementation extends PypiBase {
]
}
static get defaultBadgeData() {
return { label: 'implementation' }
}
static render({ implementations }) {
return {
message: implementations.sort().join(' | '),

View File

@@ -12,10 +12,6 @@ module.exports = class PypiPythonVersions extends PypiBase {
return this.buildRoute('pypi/pyversions')
}
static get defaultBadgeData() {
return { label: 'python' }
}
static get examples() {
return [
{
@@ -27,6 +23,10 @@ module.exports = class PypiPythonVersions extends PypiBase {
]
}
static get defaultBadgeData() {
return { label: 'python' }
}
static render({ versions }) {
const versionSet = new Set(versions)
// We only show v2 if eg. v2.4 does not appear.

View File

@@ -12,10 +12,6 @@ module.exports = class PypiStatus extends PypiBase {
return this.buildRoute('pypi/status')
}
static get defaultBadgeData() {
return { label: 'status' }
}
static get examples() {
return [
{
@@ -28,6 +24,10 @@ module.exports = class PypiStatus extends PypiBase {
]
}
static get defaultBadgeData() {
return { label: 'status' }
}
static render({ status = '' }) {
status = status.toLowerCase()

View File

@@ -12,10 +12,6 @@ module.exports = class PypiVersion extends PypiBase {
return this.buildRoute('pypi/v')
}
static get defaultBadgeData() {
return { label: 'pypi' }
}
static get examples() {
return [
{
@@ -28,6 +24,10 @@ module.exports = class PypiVersion extends PypiBase {
]
}
static get defaultBadgeData() {
return { label: 'pypi' }
}
static render({ version }) {
return renderVersionBadge({ version })
}

View File

@@ -12,10 +12,6 @@ module.exports = class PypiWheel extends PypiBase {
return this.buildRoute('pypi/wheel')
}
static get defaultBadgeData() {
return { label: 'wheel' }
}
static get examples() {
return [
{
@@ -28,6 +24,10 @@ module.exports = class PypiWheel extends PypiBase {
]
}
static get defaultBadgeData() {
return { label: 'wheel' }
}
static render({ hasWheel }) {
if (hasWheel) {
return {

View File

@@ -14,11 +14,6 @@ const schema = Joi.object({
})
class BaseRedminePluginRating extends BaseXmlService {
async fetch({ plugin }) {
const url = `https://www.redmine.org/plugins/${plugin}.xml`
return this._requestXml({ schema, url })
}
static get category() {
return 'rating'
}
@@ -27,6 +22,11 @@ class BaseRedminePluginRating extends BaseXmlService {
throw new Error(`render() function not implemented for ${this.name}`)
}
async fetch({ plugin }) {
const url = `https://www.redmine.org/plugins/${plugin}.xml`
return this._requestXml({ schema, url })
}
async handle({ plugin }) {
const data = await this.fetch({ plugin })
const rating = data['redmine-plugin']['ratings-average']
@@ -42,10 +42,6 @@ class RedminePluginRating extends BaseRedminePluginRating {
}
}
static get defaultBadgeData() {
return { label: 'redmine' }
}
static get examples() {
return [
{
@@ -56,6 +52,10 @@ class RedminePluginRating extends BaseRedminePluginRating {
]
}
static get defaultBadgeData() {
return { label: 'redmine' }
}
static render({ rating }) {
return {
label: 'rating',

View File

@@ -8,6 +8,10 @@ const statusSchema = Joi.object({
}).required()
module.exports = class RequiresIo extends BaseJsonService {
static get category() {
return 'dependencies'
}
static get route() {
return {
base: 'requires',
@@ -15,42 +19,6 @@ module.exports = class RequiresIo extends BaseJsonService {
}
}
static get defaultBadgeData() {
return { label: 'requirements' }
}
async handle({ service, user, repo, branch }) {
const { status } = await this.fetch({ service, user, repo, branch })
return this.constructor.render({ status })
}
async fetch({ service, user, repo, branch }) {
const url = `https://requires.io/api/v1/status/${service}/${user}/${repo}`
return this._requestJson({
url,
schema: statusSchema,
options: { qs: { branch } },
})
}
static render({ status }) {
let message = status
let color = 'lightgrey'
if (status === 'up-to-date') {
message = 'up to date'
color = 'brightgreen'
} else if (status === 'outdated') {
color = 'yellow'
} else if (status === 'insecure') {
color = 'red'
}
return { message, color }
}
static get category() {
return 'dependencies'
}
static get examples() {
return [
{
@@ -72,4 +40,36 @@ module.exports = class RequiresIo extends BaseJsonService {
},
]
}
static get defaultBadgeData() {
return { label: 'requirements' }
}
static render({ status }) {
let message = status
let color = 'lightgrey'
if (status === 'up-to-date') {
message = 'up to date'
color = 'brightgreen'
} else if (status === 'outdated') {
color = 'yellow'
} else if (status === 'insecure') {
color = 'red'
}
return { message, color }
}
async fetch({ service, user, repo, branch }) {
const url = `https://requires.io/api/v1/status/${service}/${user}/${repo}`
return this._requestJson({
url,
schema: statusSchema,
options: { qs: { branch } },
})
}
async handle({ service, user, repo, branch }) {
const { status } = await this.fetch({ service, user, repo, branch })
return this.constructor.render({ status })
}
}

View File

@@ -40,17 +40,6 @@ const legacyApiSchema = Joi.array()
.required()
module.exports = class SonarBase extends BaseJsonService {
transform({ json, sonarVersion }) {
const useLegacyApi = isLegacyVersion({ sonarVersion })
const rawValue = useLegacyApi
? json[0].msr[0].val
: json.component.measures[0].value
const value = parseInt(rawValue)
// Most values are numeric, but not all of them.
return { metricValue: value || rawValue }
}
async fetch({ sonarVersion, protocol, host, component, metricName }) {
let qs, url
const useLegacyApi = isLegacyVersion({ sonarVersion })
@@ -88,4 +77,15 @@ module.exports = class SonarBase extends BaseJsonService {
},
})
}
transform({ json, sonarVersion }) {
const useLegacyApi = isLegacyVersion({ sonarVersion })
const rawValue = useLegacyApi
? json[0].msr[0].val
: json.component.measures[0].value
const value = parseInt(rawValue)
// Most values are numeric, but not all of them.
return { metricValue: value || rawValue }
}
}

View File

@@ -16,8 +16,11 @@ module.exports = class StackExchangeMonthlyQuestions extends BaseJsonService {
return 'chat'
}
static get defaultBadgeData() {
return { label: 'stackoverflow' }
static get route() {
return {
base: 'stackexchange',
pattern: ':stackexchangesite/qm/:query',
}
}
static get examples() {
@@ -35,11 +38,8 @@ module.exports = class StackExchangeMonthlyQuestions extends BaseJsonService {
]
}
static get route() {
return {
base: 'stackexchange',
pattern: ':stackexchangesite/qm/:query',
}
static get defaultBadgeData() {
return { label: 'stackoverflow' }
}
static render(props) {

View File

@@ -30,10 +30,6 @@ module.exports = class StackExchangeReputation extends BaseJsonService {
}
}
static get defaultBadgeData() {
return { label: 'stackoverflow' }
}
static get examples() {
return [
{
@@ -48,6 +44,10 @@ module.exports = class StackExchangeReputation extends BaseJsonService {
]
}
static get defaultBadgeData() {
return { label: 'stackoverflow' }
}
static render({ stackexchangesite, numValue }) {
const label = `${stackexchangesite} reputation`

View File

@@ -22,8 +22,11 @@ module.exports = class StackExchangeQuestions extends BaseJsonService {
return 'chat'
}
static get defaultBadgeData() {
return { label: 'stackoverflow' }
static get route() {
return {
base: 'stackexchange',
pattern: ':stackexchangesite/t/:query',
}
}
static get examples() {
@@ -41,11 +44,8 @@ module.exports = class StackExchangeQuestions extends BaseJsonService {
]
}
static get route() {
return {
base: 'stackexchange',
pattern: ':stackexchangesite/t/:query',
}
static get defaultBadgeData() {
return { label: 'stackoverflow' }
}
static render(props) {

View File

@@ -121,6 +121,36 @@ const fileFoundOrNotSchema = Joi.alternatives(
)
class SteamCollectionSize extends BaseSteamAPI {
static get category() {
return 'other'
}
static get route() {
return {
base: 'steam/collection-files',
pattern: ':collectionId',
}
}
static get examples() {
return [
{
title: 'Steam Collection Files',
namedParams: { collectionId: '180077636' },
staticPreview: this.render({ size: 32 }),
documentation,
},
]
}
static get defaultBadgeData() {
return { label: 'files' }
}
static render({ size }) {
return { message: metric(size), color: 'brightgreen' }
}
static get interf() {
return 'ISteamRemoteStorage'
}
@@ -133,10 +163,6 @@ class SteamCollectionSize extends BaseSteamAPI {
return '1'
}
static render({ size }) {
return { message: metric(size), color: 'brightgreen' }
}
async handle({ collectionId }) {
const options = {
method: 'POST',
@@ -159,32 +185,6 @@ class SteamCollectionSize extends BaseSteamAPI {
size: json.response.collectiondetails[0].children.length,
})
}
static get category() {
return 'other'
}
static get defaultBadgeData() {
return { label: 'files' }
}
static get route() {
return {
base: 'steam/collection-files',
pattern: ':collectionId',
}
}
static get examples() {
return [
{
title: 'Steam Collection Files',
namedParams: { collectionId: '180077636' },
staticPreview: this.render({ size: 32 }),
documentation,
},
]
}
}
class SteamFileService extends BaseSteamAPI {
@@ -200,6 +200,10 @@ class SteamFileService extends BaseSteamAPI {
return '1'
}
async onRequest({ response }) {
throw new Error(`onRequest() wasn't implemented for ${this.name}`)
}
async handle({ fileId }) {
const options = {
method: 'POST',
@@ -217,29 +221,13 @@ class SteamFileService extends BaseSteamAPI {
return this.onRequest({ response: json.response.publishedfiledetails[0] })
}
async onRequest({ response }) {
throw new Error(`onRequest() wasn't implemented for ${this.name}`)
}
}
class SteamFileSize extends SteamFileService {
static render({ fileSize }) {
return { message: prettyBytes(fileSize), color: 'brightgreen' }
}
async onRequest({ response }) {
return this.constructor.render({ fileSize: response.file_size })
}
static get category() {
return 'size'
}
static get defaultBadgeData() {
return { label: 'size' }
}
static get route() {
return {
base: 'steam/size',
@@ -257,20 +245,23 @@ class SteamFileSize extends SteamFileService {
},
]
}
}
class SteamFileReleaseDate extends SteamFileService {
static render({ releaseDate }) {
return { message: formatDate(releaseDate), color: ageColor(releaseDate) }
static get defaultBadgeData() {
return { label: 'size' }
}
static render({ fileSize }) {
return { message: prettyBytes(fileSize), color: 'brightgreen' }
}
async onRequest({ response }) {
const releaseDate = new Date(0).setUTCSeconds(response.time_created)
return this.constructor.render({ releaseDate })
return this.constructor.render({ fileSize: response.file_size })
}
}
static get defaultBadgeData() {
return { label: 'release date' }
class SteamFileReleaseDate extends SteamFileService {
static get category() {
return 'activity'
}
static get route() {
@@ -293,24 +284,21 @@ class SteamFileReleaseDate extends SteamFileService {
]
}
static get category() {
return 'activity'
static get defaultBadgeData() {
return { label: 'release date' }
}
static render({ releaseDate }) {
return { message: formatDate(releaseDate), color: ageColor(releaseDate) }
}
async onRequest({ response }) {
const releaseDate = new Date(0).setUTCSeconds(response.time_created)
return this.constructor.render({ releaseDate })
}
}
class SteamFileSubscriptions extends SteamFileService {
static render({ subscriptions }) {
return { message: metric(subscriptions), color: 'brightgreen' }
}
async onRequest({ response }) {
return this.constructor.render({ subscriptions: response.subscriptions })
}
static get defaultBadgeData() {
return { label: 'subscriptions' }
}
static get category() {
return 'rating'
}
@@ -332,21 +320,21 @@ class SteamFileSubscriptions extends SteamFileService {
},
]
}
}
class SteamFileFavorites extends SteamFileService {
static render({ favorites }) {
return { message: metric(favorites), color: 'brightgreen' }
static get defaultBadgeData() {
return { label: 'subscriptions' }
}
static render({ subscriptions }) {
return { message: metric(subscriptions), color: 'brightgreen' }
}
async onRequest({ response }) {
return this.constructor.render({ favorites: response.favorited })
}
static get defaultBadgeData() {
return { label: 'favorites' }
return this.constructor.render({ subscriptions: response.subscriptions })
}
}
class SteamFileFavorites extends SteamFileService {
static get category() {
return 'rating'
}
@@ -368,27 +356,25 @@ class SteamFileFavorites extends SteamFileService {
},
]
}
}
class SteamFileDownloads extends SteamFileService {
static render({ downloads }) {
return { message: metric(downloads), color: downloadCount(downloads) }
static get defaultBadgeData() {
return { label: 'favorites' }
}
static render({ favorites }) {
return { message: metric(favorites), color: 'brightgreen' }
}
async onRequest({ response }) {
return this.constructor.render({
downloads: response.lifetime_subscriptions,
})
return this.constructor.render({ favorites: response.favorited })
}
}
class SteamFileDownloads extends SteamFileService {
static get category() {
return 'downloads'
}
static get defaultBadgeData() {
return { label: 'downloads' }
}
static get route() {
return {
base: 'steam/downloads',
@@ -406,19 +392,25 @@ class SteamFileDownloads extends SteamFileService {
},
]
}
}
class SteamFileViews extends SteamFileService {
static render({ views }) {
return { message: metric(views), color: 'brightgreen' }
static get defaultBadgeData() {
return { label: 'downloads' }
}
static render({ downloads }) {
return { message: metric(downloads), color: downloadCount(downloads) }
}
async onRequest({ response }) {
return this.constructor.render({ views: response.views })
return this.constructor.render({
downloads: response.lifetime_subscriptions,
})
}
}
static get defaultBadgeData() {
return { label: 'views' }
class SteamFileViews extends SteamFileService {
static get category() {
return 'other'
}
static get route() {
@@ -439,8 +431,16 @@ class SteamFileViews extends SteamFileService {
]
}
static get category() {
return 'other'
static get defaultBadgeData() {
return { label: 'views' }
}
static render({ views }) {
return { message: metric(views), color: 'brightgreen' }
}
async onRequest({ response }) {
return this.constructor.render({ views: response.views })
}
}

View File

@@ -15,8 +15,8 @@ const validatorSchema = Joi.object()
.required()
module.exports = class SwaggerValidatorService extends BaseJsonService {
static render({ message, clr }) {
return { message, color: clr }
static get category() {
return 'other'
}
static get route() {
@@ -26,38 +26,6 @@ module.exports = class SwaggerValidatorService extends BaseJsonService {
}
}
static get defaultBadgeData() {
return { label: 'swagger' }
}
async handle({ scheme, url }) {
const json = await this.fetch({ scheme, urlF: url })
const valMessages = json.schemaValidationMessages
if (!valMessages || valMessages.length === 0) {
return this.constructor.render({ message: 'valid', clr: 'brightgreen' })
} else {
return this.constructor.render({ message: 'invalid', clr: 'red' })
}
}
async fetch({ scheme, urlF }) {
const url = 'http://online.swagger.io/validator/debug'
return this._requestJson({
url,
schema: validatorSchema,
options: {
qs: {
url: `${scheme}://${urlF}`,
},
},
})
}
static get category() {
return 'other'
}
static get examples() {
return [
{
@@ -72,4 +40,36 @@ module.exports = class SwaggerValidatorService extends BaseJsonService {
},
]
}
static get defaultBadgeData() {
return { label: 'swagger' }
}
static render({ message, clr }) {
return { message, color: clr }
}
async fetch({ scheme, urlF }) {
const url = 'http://online.swagger.io/validator/debug'
return this._requestJson({
url,
schema: validatorSchema,
options: {
qs: {
url: `${scheme}://${urlF}`,
},
},
})
}
async handle({ scheme, url }) {
const json = await this.fetch({ scheme, urlF: url })
const valMessages = json.schemaValidationMessages
if (!valMessages || valMessages.length === 0) {
return this.constructor.render({ message: 'valid', clr: 'brightgreen' })
} else {
return this.constructor.render({ message: 'invalid', clr: 'red' })
}
}
}

View File

@@ -47,16 +47,16 @@ const gradeColors = {
}
class SymfonyInsightBase extends BaseXmlService {
static get category() {
return 'analysis'
}
static get defaultBadgeData() {
return {
label: 'symfony insight',
}
}
static get category() {
return 'analysis'
}
async fetch({ projectUuid }) {
const url = `https://insight.symfony.com/api/projects/${projectUuid}`
const options = {

View File

@@ -7,24 +7,6 @@ const {
} = require('./symfony-insight-base')
module.exports = class SymfonyInsightGrade extends SymfonyInsightBase {
static render({ status, grade }) {
const label = 'grade'
if (status !== 'finished' && status !== '') {
return {
label,
message: 'pending',
color: 'lightgrey',
}
}
const message = grade === 'none' ? 'no medal' : grade
return {
label,
message,
color: gradeColors[grade],
}
}
static get route() {
return {
base: 'symfony/i/grade',
@@ -48,6 +30,24 @@ module.exports = class SymfonyInsightGrade extends SymfonyInsightBase {
]
}
static render({ status, grade }) {
const label = 'grade'
if (status !== 'finished' && status !== '') {
return {
label,
message: 'pending',
color: 'lightgrey',
}
}
const message = grade === 'none' ? 'no medal' : grade
return {
label,
message,
color: gradeColors[grade],
}
}
async handle({ projectUuid }) {
const data = await this.fetch({ projectUuid })
const { grade, status } = this.transform({ data })

View File

@@ -16,23 +16,6 @@ const gradeStars = {
}
module.exports = class SymfonyInsightStars extends SymfonyInsightBase {
static render({ status, grade }) {
const label = 'stars'
if (status !== 'finished' && status !== '') {
return {
label,
message: 'pending',
color: 'lightgrey',
}
}
const numStars = gradeStars[grade]
return {
label,
message: starRating(numStars, 4),
color: gradeColors[grade],
}
}
static get route() {
return {
base: 'symfony/i/stars',
@@ -56,6 +39,23 @@ module.exports = class SymfonyInsightStars extends SymfonyInsightBase {
]
}
static render({ status, grade }) {
const label = 'stars'
if (status !== 'finished' && status !== '') {
return {
label,
message: 'pending',
color: 'lightgrey',
}
}
const numStars = gradeStars[grade]
return {
label,
message: starRating(numStars, 4),
color: gradeColors[grade],
}
}
async handle({ projectUuid }) {
const data = await this.fetch({ projectUuid })
const { grade, status } = this.transform({ data })

View File

@@ -3,6 +3,29 @@
const { SymfonyInsightBase, keywords } = require('./symfony-insight-base')
module.exports = class SymfonyInsightViolations extends SymfonyInsightBase {
static get route() {
return {
base: 'symfony/i/violations',
pattern: ':projectUuid',
}
}
static get examples() {
return [
{
title: 'SymfonyInsight Violations',
namedParams: {
projectUuid: '45afb680-d4e6-4e66-93ea-bcfa79eb8a87',
},
staticPreview: this.render({
numViolations: 0,
status: 'finished',
}),
keywords,
},
]
}
static render({
status,
numViolations,
@@ -54,29 +77,6 @@ module.exports = class SymfonyInsightViolations extends SymfonyInsightBase {
}
}
static get route() {
return {
base: 'symfony/i/violations',
pattern: ':projectUuid',
}
}
static get examples() {
return [
{
title: 'SymfonyInsight Violations',
namedParams: {
projectUuid: '45afb680-d4e6-4e66-93ea-bcfa79eb8a87',
},
staticPreview: this.render({
numViolations: 0,
status: 'finished',
}),
keywords,
},
]
}
async handle({ projectUuid }) {
const data = await this.fetch({ projectUuid })
const lastAnalysis = this.transform({ data })

View File

@@ -15,31 +15,6 @@ const buildStatusSchema = Joi.object({
}).required()
module.exports = class TeamCityBuild extends TeamCityBase {
static render({ status, statusText, useVerbose }) {
if (status === 'SUCCESS') {
return {
message: 'passing',
color: 'brightgreen',
}
} else if (statusText && useVerbose) {
return {
message: statusText.toLowerCase(),
color: 'red',
}
} else {
return {
message: status.toLowerCase(),
color: 'red',
}
}
}
static get defaultBadgeData() {
return {
label: 'build',
}
}
static get category() {
return 'build'
}
@@ -94,6 +69,31 @@ module.exports = class TeamCityBuild extends TeamCityBase {
]
}
static get defaultBadgeData() {
return {
label: 'build',
}
}
static render({ status, statusText, useVerbose }) {
if (status === 'SUCCESS') {
return {
message: 'passing',
color: 'brightgreen',
}
} else if (statusText && useVerbose) {
return {
message: statusText.toLowerCase(),
color: 'red',
}
} else {
return {
message: status.toLowerCase(),
color: 'red',
}
}
}
async handle({ protocol, hostAndPath, verbosity, buildId }) {
// JetBrains Docs: https://confluence.jetbrains.com/display/TCD18/REST+API#RESTAPI-BuildStatusIcon
const buildLocator = `buildType:(id:${buildId})`

View File

@@ -17,19 +17,6 @@ const buildStatisticsSchema = Joi.object({
}).required()
module.exports = class TeamCityCoverage extends TeamCityBase {
static render({ coverage }) {
return {
message: `${coverage.toFixed(0)}%`,
color: coveragePercentage(coverage),
}
}
static get defaultBadgeData() {
return {
label: 'coverage',
}
}
static get category() {
return 'coverage'
}
@@ -69,21 +56,17 @@ module.exports = class TeamCityCoverage extends TeamCityBase {
]
}
async handle({ protocol, hostAndPath, buildId }) {
// JetBrains Docs: https://confluence.jetbrains.com/display/TCD18/REST+API#RESTAPI-Statistics
const buildLocator = `buildType:(id:${buildId})`
const apiPath = `app/rest/builds/${encodeURIComponent(
buildLocator
)}/statistics`
const data = await this.fetch({
protocol,
hostAndPath,
apiPath,
schema: buildStatisticsSchema,
})
static get defaultBadgeData() {
return {
label: 'coverage',
}
}
const { coverage } = this.transform({ data })
return this.constructor.render({ coverage })
static render({ coverage }) {
return {
message: `${coverage.toFixed(0)}%`,
color: coveragePercentage(coverage),
}
}
transform({ data }) {
@@ -104,4 +87,21 @@ module.exports = class TeamCityCoverage extends TeamCityBase {
throw new InvalidResponse({ prettyMessage: 'no coverage data available' })
}
async handle({ protocol, hostAndPath, buildId }) {
// JetBrains Docs: https://confluence.jetbrains.com/display/TCD18/REST+API#RESTAPI-Statistics
const buildLocator = `buildType:(id:${buildId})`
const apiPath = `app/rest/builds/${encodeURIComponent(
buildLocator
)}/statistics`
const data = await this.fetch({
protocol,
hostAndPath,
apiPath,
schema: buildStatisticsSchema,
})
const { coverage } = this.transform({ data })
return this.constructor.render({ coverage })
}
}

View File

@@ -94,14 +94,6 @@ class TwitterFollow extends BaseJsonService {
}
}
async fetch({ user }) {
return this._requestJson({
schema,
url: `http://cdn.syndication.twimg.com/widgets/followbutton/info.json`,
options: { qs: { screen_names: user } },
})
}
static render({ user, followers }) {
return {
label: `follow @${user}`,
@@ -114,6 +106,14 @@ class TwitterFollow extends BaseJsonService {
}
}
async fetch({ user }) {
return this._requestJson({
schema,
url: `http://cdn.syndication.twimg.com/widgets/followbutton/info.json`,
options: { qs: { screen_names: user } },
})
}
async handle({ user }) {
const data = await this.fetch({ user })
if (data.length === 0) {

View File

@@ -6,12 +6,6 @@ const UptimeRobotBase = require('./uptimerobot-base')
const ratioColor = colorScale([10, 30, 50, 70])
module.exports = class UptimeRobotRatio extends UptimeRobotBase {
static get defaultBadgeData() {
return {
label: 'uptime',
}
}
static get route() {
return {
base: 'uptimerobot/ratio',
@@ -40,6 +34,12 @@ module.exports = class UptimeRobotRatio extends UptimeRobotBase {
]
}
static get defaultBadgeData() {
return {
label: 'uptime',
}
}
static render({ ratio }) {
return {
message: `${ratio}%`,

View File

@@ -3,12 +3,6 @@
const UptimeRobotBase = require('./uptimerobot-base')
module.exports = class UptimeRobotStatus extends UptimeRobotBase {
static get defaultBadgeData() {
return {
label: 'status',
}
}
static get route() {
return {
base: 'uptimerobot/status',
@@ -28,6 +22,12 @@ module.exports = class UptimeRobotStatus extends UptimeRobotBase {
]
}
static get defaultBadgeData() {
return {
label: 'status',
}
}
static render({ status }) {
switch (status) {
case 0:

View File

@@ -26,19 +26,6 @@ module.exports = class VisualStudioMarketplaceAzureDevOpsInstalls extends Visual
}
}
static get defaultBadgeData() {
return {
label: 'installs',
}
}
static render({ count }) {
return {
message: metric(count),
color: downloadCount(count),
}
}
static get examples() {
return [
{
@@ -54,6 +41,19 @@ module.exports = class VisualStudioMarketplaceAzureDevOpsInstalls extends Visual
]
}
static get defaultBadgeData() {
return {
label: 'installs',
}
}
static render({ count }) {
return {
message: metric(count),
color: downloadCount(count),
}
}
async handle({ measure, extensionId }) {
const json = await this.fetch({ extensionId })
const { statistics } = this.transformStatistics({ json })

View File

@@ -26,16 +26,6 @@ module.exports = class VisualStudioMarketplaceDownloads extends VisualStudioMark
}
}
static render({ measure, count }) {
const label = measure === 'd' ? 'downloads' : 'installs'
return {
label,
message: metric(count),
color: downloadCount(count),
}
}
static get examples() {
return [
{
@@ -57,6 +47,16 @@ module.exports = class VisualStudioMarketplaceDownloads extends VisualStudioMark
]
}
static render({ measure, count }) {
const label = measure === 'd' ? 'downloads' : 'installs'
return {
label,
message: metric(count),
color: downloadCount(count),
}
}
async handle({ measure, extensionId }) {
const json = await this.fetch({ extensionId })
const { statistics } = this.transformStatistics({ json })

View File

@@ -17,23 +17,6 @@ module.exports = class VisualStudioMarketplaceRating extends VisualStudioMarketp
}
}
static get defaultBadgeData() {
return {
label: 'rating',
}
}
static render({ format, averageRating, ratingCount }) {
const message =
format === 'r'
? `${averageRating.toFixed(1)}/5 (${ratingCount})`
: starRating(averageRating)
return {
message,
color: floorCount(averageRating, 2, 3, 4),
}
}
static get examples() {
return [
{
@@ -60,6 +43,23 @@ module.exports = class VisualStudioMarketplaceRating extends VisualStudioMarketp
]
}
static get defaultBadgeData() {
return {
label: 'rating',
}
}
static render({ format, averageRating, ratingCount }) {
const message =
format === 'r'
? `${averageRating.toFixed(1)}/5 (${ratingCount})`
: starRating(averageRating)
return {
message,
color: floorCount(averageRating, 2, 3, 4),
}
}
async handle({ format, extensionId }) {
const json = await this.fetch({ extensionId })
const { statistics } = this.transformStatistics({ json })

View File

@@ -15,16 +15,6 @@ module.exports = class VisualStudioMarketplaceVersion extends VisualStudioMarket
}
}
static get defaultBadgeData() {
return {
label: 'version',
}
}
static render({ version }) {
return renderVersionBadge({ version })
}
static get examples() {
return [
{
@@ -37,6 +27,16 @@ module.exports = class VisualStudioMarketplaceVersion extends VisualStudioMarket
]
}
static get defaultBadgeData() {
return {
label: 'version',
}
}
static render({ version }) {
return renderVersionBadge({ version })
}
transform({ json }) {
const { extension } = this.transformExtension({ json })
const version = extension.versions[0].version

View File

@@ -23,33 +23,15 @@ module.exports = class WaffleLabel extends BaseJsonService {
return 'issue-tracking'
}
static get route() {
return {
base: 'waffle/label',
pattern: ':user/:repo/:label',
}
}
static get defaultBadgeData() {
return { label: 'waffle' }
}
static get isDeprecated() {
const now = new Date()
return now.getTime() >= new Date('2019-05-16')
}
static render({ label, color, count }) {
if (count === 'absent') {
return { message: count }
}
if (count === 0 || !color) {
color = '78bdf2'
}
static get route() {
return {
label,
message: metric(count),
color,
base: 'waffle/label',
pattern: ':user/:repo/:label',
}
}
@@ -71,6 +53,24 @@ module.exports = class WaffleLabel extends BaseJsonService {
]
}
static get defaultBadgeData() {
return { label: 'waffle' }
}
static render({ label, color, count }) {
if (count === 'absent') {
return { message: count }
}
if (count === 0 || !color) {
color = '78bdf2'
}
return {
label,
message: metric(count),
color,
}
}
async fetch({ user, repo }) {
const url = `https://api.waffle.io/${user}/${repo}/columns`
return this._requestJson({

View File

@@ -15,53 +15,6 @@ const werckerSchema = Joi.array()
.required()
module.exports = class Wercker extends BaseJsonService {
static getBaseUrl({ projectId, applicationName }) {
if (applicationName) {
return `https://app.wercker.com/api/v3/applications/${applicationName}/builds`
} else {
return `https://app.wercker.com/api/v3/runs?applicationId=${projectId}`
}
}
async fetch({ baseUrl, branch }) {
return this._requestJson({
schema: werckerSchema,
url: baseUrl,
options: {
qs: {
branch,
limit: 1,
},
},
errorMessages: {
401: 'private application not supported',
404: 'application not found',
},
})
}
static render({ result }) {
return renderBuildStatusBadge({ status: result })
}
async handle({ projectId, applicationName, branch }) {
const json = await this.fetch({
baseUrl: this.constructor.getBaseUrl({
projectId,
applicationName,
}),
branch,
})
if (json.length === 0) {
return this.constructor.render({
result: 'not built',
})
}
const { result } = json[0]
return this.constructor.render({ result })
}
// Metadata
static get category() {
return 'build'
}
@@ -113,4 +66,50 @@ module.exports = class Wercker extends BaseJsonService {
},
]
}
static render({ result }) {
return renderBuildStatusBadge({ status: result })
}
static getBaseUrl({ projectId, applicationName }) {
if (applicationName) {
return `https://app.wercker.com/api/v3/applications/${applicationName}/builds`
} else {
return `https://app.wercker.com/api/v3/runs?applicationId=${projectId}`
}
}
async fetch({ baseUrl, branch }) {
return this._requestJson({
schema: werckerSchema,
url: baseUrl,
options: {
qs: {
branch,
limit: 1,
},
},
errorMessages: {
401: 'private application not supported',
404: 'application not found',
},
})
}
async handle({ projectId, applicationName, branch }) {
const json = await this.fetch({
baseUrl: this.constructor.getBaseUrl({
projectId,
applicationName,
}),
branch,
})
if (json.length === 0) {
return this.constructor.render({
result: 'not built',
})
}
const { result } = json[0]
return this.constructor.render({ result })
}
}

View File

@@ -11,6 +11,43 @@ const wheelmapSchema = Joi.object({
}).required()
module.exports = class Wheelmap extends BaseJsonService {
static get category() {
return 'other'
}
static get route() {
return {
base: 'wheelmap/a',
pattern: ':nodeId(-?[0-9]+)',
}
}
static get examples() {
return [
{
title: 'Wheelmap',
namedParams: { nodeId: '26699541' },
staticPreview: this.render({ accessibility: 'yes' }),
},
]
}
static get defaultBadgeData() {
return { label: 'accessibility' }
}
static render({ accessibility }) {
let color
if (accessibility === 'yes') {
color = 'brightgreen'
} else if (accessibility === 'limited') {
color = 'yellow'
} else if (accessibility === 'no') {
color = 'red'
}
return { message: accessibility, color }
}
async fetch({ nodeId }) {
let options
if (serverSecrets.wheelmap_token) {
@@ -32,46 +69,9 @@ module.exports = class Wheelmap extends BaseJsonService {
})
}
static render({ accessibility }) {
let color
if (accessibility === 'yes') {
color = 'brightgreen'
} else if (accessibility === 'limited') {
color = 'yellow'
} else if (accessibility === 'no') {
color = 'red'
}
return { message: accessibility, color }
}
async handle({ nodeId }) {
const json = await this.fetch({ nodeId })
const accessibility = json.node.wheelchair
return this.constructor.render({ accessibility })
}
static get defaultBadgeData() {
return { label: 'accessibility' }
}
static get category() {
return 'other'
}
static get route() {
return {
base: 'wheelmap/a',
pattern: ':nodeId(-?[0-9]+)',
}
}
static get examples() {
return [
{
title: 'Wheelmap',
namedParams: { nodeId: '26699541' },
staticPreview: this.render({ accessibility: 'yes' }),
},
]
}
}

View File

@@ -29,29 +29,10 @@ function DownloadsForExtensionType(extensionType) {
return `Wordpress${capt}Downloads`
}
static render({ downloads }) {
return {
message: metric(downloads),
color: downloadCount(downloads),
}
}
async handle({ slug }) {
const { downloaded: downloads } = await this.fetch({
extensionType,
slug,
})
return this.constructor.render({ downloads })
}
static get category() {
return 'downloads'
}
static get defaultBadgeData() {
return { label: 'downloads' }
}
static get route() {
return {
base: `wordpress/${extensionType}/dt`,
@@ -68,6 +49,25 @@ function DownloadsForExtensionType(extensionType) {
},
]
}
static get defaultBadgeData() {
return { label: 'downloads' }
}
static render({ downloads }) {
return {
message: metric(downloads),
color: downloadCount(downloads),
}
}
async handle({ slug }) {
const { downloaded: downloads } = await this.fetch({
extensionType,
slug,
})
return this.constructor.render({ downloads })
}
}
}
@@ -83,25 +83,6 @@ function InstallsForExtensionType(extensionType) {
return 'downloads'
}
static render({ installCount }) {
return {
message: metric(installCount),
color: downloadCount(installCount),
}
}
async handle({ slug }) {
const { active_installs: installCount } = await this.fetch({
extensionType,
slug,
})
return this.constructor.render({ installCount })
}
static get defaultBadgeData() {
return { label: 'active installs' }
}
static get route() {
return {
base: `wordpress/${extensionType}/installs`,
@@ -118,6 +99,25 @@ function InstallsForExtensionType(extensionType) {
},
]
}
static get defaultBadgeData() {
return { label: 'active installs' }
}
static render({ installCount }) {
return {
message: metric(installCount),
color: downloadCount(installCount),
}
}
async handle({ slug }) {
const { active_installs: installCount } = await this.fetch({
extensionType,
slug,
})
return this.constructor.render({ installCount })
}
}
}
@@ -158,10 +158,6 @@ function DownloadsForInterval(interval) {
return 'downloads'
}
static get defaultBadgeData() {
return { label: 'downloads' }
}
static get route() {
return {
base,
@@ -179,6 +175,10 @@ function DownloadsForInterval(interval) {
]
}
static get defaultBadgeData() {
return { label: 'downloads' }
}
static render({ downloads }) {
return {
message: `${metric(downloads)}${messageSuffix}`,

View File

@@ -52,10 +52,6 @@ class WordpressPluginTestedVersion extends BaseWordpress {
return 'platform-support'
}
static get defaultBadgeData() {
return { label: 'wordpress' }
}
static get route() {
return {
base: `wordpress/plugin/tested`,
@@ -75,6 +71,10 @@ class WordpressPluginTestedVersion extends BaseWordpress {
]
}
static get defaultBadgeData() {
return { label: 'wordpress' }
}
static renderStaticPreview({ testedVersion }) {
// Since this badge has an async `render()` function, but `get examples()` has to
// be synchronous, this method exists. It should return the same value as the