From b71f812b68527b507262b2da4f74e4ffcc53f07a Mon Sep 17 00:00:00 2001
From: chris48s <chris48s@users.noreply.github.com>
Date: Fri, 22 Dec 2023 13:25:38 +0000
Subject: [PATCH] migrate examples to openApi part 17; affects [buildkite cii
 codeship crates jsdelivr npms] and bundlephobia (#9584)

* update crates service test

* migrate some services from examples to openApi

* migrate crates from examples to openApi, improve titles

* explain what hd,hw,hm,hy actually mean

* improve descriptions
---
 services/buildkite/buildkite.service.js       |  39 +++---
 services/bundlephobia/bundlephobia.service.js | 121 ++++++++++++------
 .../cii-best-practices.service.js             |  51 +++-----
 services/codeship/codeship.service.js         |  39 +++---
 services/crates/crates-base.js                |   7 +-
 services/crates/crates-downloads.service.js   |  79 ++++++------
 services/crates/crates-license.service.js     |  44 ++++---
 services/crates/crates-license.tester.js      |   2 +-
 services/crates/crates-version.service.js     |  22 ++--
 .../jsdelivr/jsdelivr-hits-github.service.js  |   1 +
 .../jsdelivr/jsdelivr-hits-npm.service.js     |  54 +++++---
 services/npms-io/npms-io-score.service.js     |  70 +++++-----
 12 files changed, 312 insertions(+), 217 deletions(-)

diff --git a/services/buildkite/buildkite.service.js b/services/buildkite/buildkite.service.js
index e881421cfc..c9612b6e3c 100644
--- a/services/buildkite/buildkite.service.js
+++ b/services/buildkite/buildkite.service.js
@@ -1,6 +1,6 @@
 import Joi from 'joi'
 import { isBuildStatus, renderBuildStatusBadge } from '../build-status.js'
-import { BaseJsonService } from '../index.js'
+import { BaseJsonService, pathParams } from '../index.js'
 
 // unknown is a valid 'other' status for Buildkite
 const schema = Joi.object({
@@ -11,25 +11,32 @@ export default class Buildkite extends BaseJsonService {
   static category = 'build'
   static route = { base: 'buildkite', pattern: ':identifier/:branch*' }
 
-  static examples = [
-    {
-      title: 'Buildkite',
-      pattern: ':identifier',
-      namedParams: {
-        identifier: '3826789cf8890b426057e6fe1c4e683bdf04fa24d498885489',
+  static openApi = {
+    '/buildkite/{identifier}': {
+      get: {
+        summary: 'Buildkite',
+        parameters: pathParams({
+          name: 'identifier',
+          example: '3826789cf8890b426057e6fe1c4e683bdf04fa24d498885489',
+        }),
       },
-      staticPreview: renderBuildStatusBadge({ status: 'passing' }),
     },
-    {
-      title: 'Buildkite (branch)',
-      pattern: ':identifier/:branch',
-      namedParams: {
-        identifier: '3826789cf8890b426057e6fe1c4e683bdf04fa24d498885489',
-        branch: 'master',
+    '/buildkite/{identifier}/{branch}': {
+      get: {
+        summary: 'Buildkite (branch)',
+        parameters: pathParams(
+          {
+            name: 'identifier',
+            example: '3826789cf8890b426057e6fe1c4e683bdf04fa24d498885489',
+          },
+          {
+            name: 'branch',
+            example: 'master',
+          },
+        ),
       },
-      staticPreview: renderBuildStatusBadge({ status: 'passing' }),
     },
-  ]
+  }
 
   static defaultBadgeData = { label: 'build' }
 
diff --git a/services/bundlephobia/bundlephobia.service.js b/services/bundlephobia/bundlephobia.service.js
index 26a9cd77e0..0b182d59f8 100644
--- a/services/bundlephobia/bundlephobia.service.js
+++ b/services/bundlephobia/bundlephobia.service.js
@@ -1,14 +1,15 @@
 import Joi from 'joi'
 import prettyBytes from 'pretty-bytes'
 import { nonNegativeInteger } from '../validators.js'
-import { BaseJsonService } from '../index.js'
+import { BaseJsonService, pathParams } from '../index.js'
 
 const schema = Joi.object({
   size: nonNegativeInteger,
   gzip: nonNegativeInteger,
 }).required()
 
-const keywords = ['node', 'bundlephobia']
+const description =
+  '[Bundlephobia](https://bundlephobia.com) lets you understand the size of a javascript package from NPM before it becomes a part of your bundle.'
 
 export default class Bundlephobia extends BaseJsonService {
   static category = 'size'
@@ -18,52 +19,92 @@ export default class Bundlephobia extends BaseJsonService {
     pattern: ':format(min|minzip)/:scope(@[^/]+)?/:packageName/:version?',
   }
 
-  static examples = [
-    {
-      title: 'npm bundle size',
-      pattern: ':format(min|minzip)/:packageName',
-      namedParams: {
-        format: 'min',
-        packageName: 'react',
+  static openApi = {
+    '/bundlephobia/{format}/{packageName}': {
+      get: {
+        summary: 'npm bundle size',
+        description,
+        parameters: pathParams(
+          {
+            name: 'format',
+            schema: { type: 'string', enum: this.getEnum('format') },
+            example: 'min',
+          },
+          {
+            name: 'packageName',
+            example: 'react',
+          },
+        ),
       },
-      staticPreview: this.render({ format: 'min', size: 6652 }),
-      keywords,
     },
-    {
-      title: 'npm bundle size (scoped)',
-      pattern: ':format(min|minzip)/:scope/:packageName',
-      namedParams: {
-        format: 'min',
-        scope: '@cycle',
-        packageName: 'core',
+    '/bundlephobia/{format}/{scope}/{packageName}': {
+      get: {
+        summary: 'npm bundle size (scoped)',
+        description,
+        parameters: pathParams(
+          {
+            name: 'format',
+            schema: { type: 'string', enum: this.getEnum('format') },
+            example: 'min',
+          },
+          {
+            name: 'scope',
+            example: '@cycle',
+          },
+          {
+            name: 'packageName',
+            example: 'core',
+          },
+        ),
       },
-      staticPreview: this.render({ format: 'min', size: 3562 }),
-      keywords,
     },
-    {
-      title: 'npm bundle size (version)',
-      pattern: ':format(min|minzip)/:packageName/:version',
-      namedParams: {
-        format: 'min',
-        packageName: 'react',
-        version: '15.0.0',
+    '/bundlephobia/{format}/{packageName}/{version}': {
+      get: {
+        summary: 'npm bundle size (version)',
+        description,
+        parameters: pathParams(
+          {
+            name: 'format',
+            schema: { type: 'string', enum: this.getEnum('format') },
+            example: 'min',
+          },
+          {
+            name: 'packageName',
+            example: 'react',
+          },
+          {
+            name: 'version',
+            example: '15.0.0',
+          },
+        ),
       },
-      staticPreview: this.render({ format: 'min', size: 20535 }),
-      keywords,
     },
-    {
-      title: 'npm bundle size (scoped version)',
-      pattern: ':format(min|minzip)/:scope/:packageName/:version',
-      namedParams: {
-        format: 'min',
-        scope: '@cycle',
-        packageName: 'core',
-        version: '7.0.0',
+    '/bundlephobia/{format}/{scope}/{packageName}/{version}': {
+      get: {
+        summary: 'npm bundle size (scoped version)',
+        description,
+        parameters: pathParams(
+          {
+            name: 'format',
+            schema: { type: 'string', enum: this.getEnum('format') },
+            example: 'min',
+          },
+          {
+            name: 'scope',
+            example: '@cycle',
+          },
+          {
+            name: 'packageName',
+            example: 'core',
+          },
+          {
+            name: 'version',
+            example: '7.0.0',
+          },
+        ),
       },
-      staticPreview: this.render({ format: 'min', size: 3562 }),
-      keywords,
     },
-  ]
+  }
 
   static _cacheLength = 900
 
diff --git a/services/cii-best-practices/cii-best-practices.service.js b/services/cii-best-practices/cii-best-practices.service.js
index b83a9013c5..ae1263fc2b 100644
--- a/services/cii-best-practices/cii-best-practices.service.js
+++ b/services/cii-best-practices/cii-best-practices.service.js
@@ -1,14 +1,12 @@
 import Joi from 'joi'
 import { colorScale, coveragePercentage } from '../color-formatters.js'
-import { BaseJsonService } from '../index.js'
+import { BaseJsonService, pathParams } from '../index.js'
 
 const schema = Joi.object({
   badge_level: Joi.string().required(),
   tiered_percentage: Joi.number().required(),
 }).required()
 
-const keywords = ['core infrastructure initiative']
-
 const summaryColorScale = colorScale(
   [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 200, 300],
   [
@@ -35,37 +33,26 @@ export default class CIIBestPracticesService extends BaseJsonService {
     pattern: ':metric(level|percentage|summary)/:projectId',
   }
 
-  static examples = [
-    {
-      title: 'CII Best Practices Level',
-      pattern: 'level/:projectId',
-      namedParams: {
-        projectId: '1',
-      },
-      staticPreview: this.renderLevelBadge({ level: 'gold' }),
-      keywords,
-    },
-    {
-      title: 'CII Best Practices Tiered Percentage',
-      pattern: 'percentage/:projectId',
-      namedParams: {
-        projectId: '29',
+  static openApi = {
+    '/cii/{metric}/{projectId}': {
+      get: {
+        summary: 'CII Best Practices',
+        description:
+          'The Core Infrastructure Initiative (CII) Best Practices badge is a way for Open Source projects to show that they follow best practices',
+        parameters: pathParams(
+          {
+            name: 'metric',
+            example: 'level',
+            schema: { type: 'string', enum: this.getEnum('metric') },
+          },
+          {
+            name: 'projectId',
+            example: '1',
+          },
+        ),
       },
-      staticPreview: this.renderTieredPercentageBadge({ percentage: 107 }),
-      keywords,
     },
-    {
-      title: 'CII Best Practices Summary',
-      pattern: 'summary/:projectId',
-      namedParams: {
-        projectId: '33',
-      },
-      staticPreview: this.renderSummaryBadge({ percentage: 94 }),
-      keywords,
-      documentation:
-        'This badge uses the same message and color scale as the native CII one, but with all the configuration and goodness that Shields provides!',
-    },
-  ]
+  }
 
   static defaultBadgeData = { label: 'cii' }
 
diff --git a/services/codeship/codeship.service.js b/services/codeship/codeship.service.js
index 8ddc631acc..6aaa013620 100644
--- a/services/codeship/codeship.service.js
+++ b/services/codeship/codeship.service.js
@@ -1,6 +1,6 @@
 import Joi from 'joi'
 import { isBuildStatus, renderBuildStatusBadge } from '../build-status.js'
-import { BaseSvgScrapingService } from '../index.js'
+import { BaseSvgScrapingService, pathParams } from '../index.js'
 
 const schema = Joi.object({
   message: Joi.alternatives()
@@ -28,25 +28,32 @@ export default class Codeship extends BaseSvgScrapingService {
   static category = 'build'
   static route = { base: 'codeship', pattern: ':projectId/:branch*' }
 
-  static examples = [
-    {
-      title: 'Codeship',
-      pattern: ':projectId',
-      namedParams: {
-        projectId: 'd6c1ddd0-16a3-0132-5f85-2e35c05e22b1',
+  static openApi = {
+    '/codeship/{projectId}': {
+      get: {
+        summary: 'Codeship',
+        parameters: pathParams({
+          name: 'projectId',
+          example: 'd6c1ddd0-16a3-0132-5f85-2e35c05e22b1',
+        }),
       },
-      staticPreview: renderBuildStatusBadge({ status: 'passing' }),
     },
-    {
-      title: 'Codeship (branch)',
-      pattern: ':projectId/:branch',
-      namedParams: {
-        projectId: '0bdb0440-3af5-0133-00ea-0ebda3a33bf6',
-        branch: 'master',
+    '/codeship/{projectId}/{branch}': {
+      get: {
+        summary: 'Codeship (branch)',
+        parameters: pathParams(
+          {
+            name: 'projectId',
+            example: '0bdb0440-3af5-0133-00ea-0ebda3a33bf6',
+          },
+          {
+            name: 'branch',
+            example: 'master',
+          },
+        ),
       },
-      staticPreview: renderBuildStatusBadge({ status: 'passing' }),
     },
-  ]
+  }
 
   static defaultBadgeData = { label: 'build' }
 
diff --git a/services/crates/crates-base.js b/services/crates/crates-base.js
index 112befc83f..aa4b7d378d 100644
--- a/services/crates/crates-base.js
+++ b/services/crates/crates-base.js
@@ -2,8 +2,6 @@ import Joi from 'joi'
 import { nonNegativeInteger } from '../validators.js'
 import { BaseJsonService } from '../index.js'
 
-const keywords = ['Rust']
-
 const crateSchema = Joi.object({
   crate: Joi.object({
     downloads: nonNegativeInteger,
@@ -49,4 +47,7 @@ class BaseCratesService extends BaseJsonService {
   }
 }
 
-export { BaseCratesService, keywords }
+const description =
+  '[Crates.io](https://crates.io/) is a package registry for Rust.'
+
+export { BaseCratesService, description }
diff --git a/services/crates/crates-downloads.service.js b/services/crates/crates-downloads.service.js
index a504f00d3a..9bd5c655bc 100644
--- a/services/crates/crates-downloads.service.js
+++ b/services/crates/crates-downloads.service.js
@@ -1,6 +1,6 @@
 import { renderDownloadsBadge } from '../downloads.js'
-import { InvalidParameter, NotFound } from '../index.js'
-import { BaseCratesService, keywords } from './crates-base.js'
+import { InvalidParameter, NotFound, pathParams } from '../index.js'
+import { BaseCratesService, description } from './crates-base.js'
 
 export default class CratesDownloads extends BaseCratesService {
   static category = 'downloads'
@@ -9,49 +9,54 @@ export default class CratesDownloads extends BaseCratesService {
     pattern: ':variant(d|dv|dr)/:crate/:version?',
   }
 
-  static examples = [
-    {
-      title: 'Crates.io',
-      pattern: 'd/:crate',
-      namedParams: {
-        crate: 'rustc-serialize',
+  static openApi = {
+    '/crates/d/{crate}': {
+      get: {
+        summary: 'Crates.io Total Downloads',
+        description,
+        parameters: pathParams({
+          name: 'crate',
+          example: 'rustc-serialize',
+        }),
       },
-      staticPreview: this.render({ variant: 'd', downloads: 5000000 }),
-      keywords,
     },
-    {
-      title: 'Crates.io (latest)',
-      pattern: 'dv/:crate',
-      namedParams: {
-        crate: 'rustc-serialize',
+    '/crates/dv/{crate}': {
+      get: {
+        summary: 'Crates.io Downloads (latest version)',
+        description,
+        parameters: pathParams({
+          name: 'crate',
+          example: 'rustc-serialize',
+        }),
       },
-      staticPreview: this.render({ variant: 'dv', downloads: 2000000 }),
-      keywords,
     },
-    {
-      title: 'Crates.io (version)',
-      pattern: 'dv/:crate/:version',
-      namedParams: {
-        crate: 'rustc-serialize',
-        version: '0.3.24',
+    '/crates/dv/{crate}/{version}': {
+      get: {
+        summary: 'Crates.io Downloads (version)',
+        description,
+        parameters: pathParams(
+          {
+            name: 'crate',
+            example: 'rustc-serialize',
+          },
+          {
+            name: 'version',
+            example: '0.3.24',
+          },
+        ),
       },
-      staticPreview: this.render({
-        variant: 'dv',
-        downloads: 2000000,
-        version: '0.3.24',
-      }),
-      keywords,
     },
-    {
-      title: 'Crates.io (recent)',
-      pattern: 'dr/:crate',
-      namedParams: {
-        crate: 'rustc-serialize',
+    '/crates/dr/{crate}': {
+      get: {
+        summary: 'Crates.io Downloads (recent)',
+        description,
+        parameters: pathParams({
+          name: 'crate',
+          example: 'rustc-serialize',
+        }),
       },
-      staticPreview: this.render({ variant: 'dr', downloads: 2000000 }),
-      keywords,
     },
-  ]
+  }
 
   static render({ variant, downloads, version }) {
     let labelOverride
diff --git a/services/crates/crates-license.service.js b/services/crates/crates-license.service.js
index 562f44841c..b59dfeb0da 100644
--- a/services/crates/crates-license.service.js
+++ b/services/crates/crates-license.service.js
@@ -1,26 +1,38 @@
-import { InvalidResponse } from '../index.js'
-import { BaseCratesService, keywords } from './crates-base.js'
+import { InvalidResponse, pathParams } from '../index.js'
+import { BaseCratesService, description } from './crates-base.js'
 
 export default class CratesLicense extends BaseCratesService {
   static category = 'license'
   static route = { base: 'crates/l', pattern: ':crate/:version?' }
 
-  static examples = [
-    {
-      title: 'Crates.io',
-      pattern: ':crate',
-      namedParams: { crate: 'rustc-serialize' },
-      staticPreview: this.render({ license: 'MIT/Apache-2.0' }),
-      keywords,
+  static openApi = {
+    '/crates/l/{crate}': {
+      get: {
+        summary: 'Crates.io License',
+        description,
+        parameters: pathParams({
+          name: 'crate',
+          example: 'rustc-serialize',
+        }),
+      },
     },
-    {
-      title: 'Crates.io',
-      pattern: ':crate/:version',
-      namedParams: { crate: 'rustc-serialize', version: '0.3.24' },
-      staticPreview: this.render({ license: 'MIT/Apache-2.0' }),
-      keywords,
+    '/crates/l/{crate}/{version}': {
+      get: {
+        summary: 'Crates.io License (version)',
+        description,
+        parameters: pathParams(
+          {
+            name: 'crate',
+            example: 'rustc-serialize',
+          },
+          {
+            name: 'version',
+            example: '0.3.24',
+          },
+        ),
+      },
     },
-  ]
+  }
 
   static defaultBadgeData = { label: 'license', color: 'blue' }
 
diff --git a/services/crates/crates-license.tester.js b/services/crates/crates-license.tester.js
index 6351c14f85..7354e876df 100644
--- a/services/crates/crates-license.tester.js
+++ b/services/crates/crates-license.tester.js
@@ -16,7 +16,7 @@ t.create('license (not found)')
 // https://github.com/badges/shields/issues/7073
 t.create('license (null licenses in history)')
   .get('/stun.json')
-  .expectBadge({ label: 'license', message: 'MIT/Apache-2.0' })
+  .expectBadge({ label: 'license', message: 'MIT OR Apache-2.0' })
 
 t.create('license (version with null license)')
   .get('/stun/0.0.1.json')
diff --git a/services/crates/crates-version.service.js b/services/crates/crates-version.service.js
index e5517899b1..e174e43ce5 100644
--- a/services/crates/crates-version.service.js
+++ b/services/crates/crates-version.service.js
@@ -1,19 +1,23 @@
 import { renderVersionBadge } from '../version.js'
-import { InvalidResponse } from '../index.js'
-import { BaseCratesService, keywords } from './crates-base.js'
+import { InvalidResponse, pathParams } from '../index.js'
+import { BaseCratesService, description } from './crates-base.js'
 
 export default class CratesVersion extends BaseCratesService {
   static category = 'version'
   static route = { base: 'crates/v', pattern: ':crate' }
 
-  static examples = [
-    {
-      title: 'Crates.io',
-      namedParams: { crate: 'rustc-serialize' },
-      staticPreview: renderVersionBadge({ version: '0.3.24' }),
-      keywords,
+  static openApi = {
+    '/crates/v/{crate}': {
+      get: {
+        summary: 'Crates.io Version',
+        description,
+        parameters: pathParams({
+          name: 'crate',
+          example: 'rustc-serialize',
+        }),
+      },
     },
-  ]
+  }
 
   transform(json) {
     if (json.errors) {
diff --git a/services/jsdelivr/jsdelivr-hits-github.service.js b/services/jsdelivr/jsdelivr-hits-github.service.js
index 96ddc830f3..4df61c2932 100644
--- a/services/jsdelivr/jsdelivr-hits-github.service.js
+++ b/services/jsdelivr/jsdelivr-hits-github.service.js
@@ -16,6 +16,7 @@ export default class JsDelivrHitsGitHub extends BaseJsDelivrService {
             name: 'period',
             example: 'hm',
             schema: { type: 'string', enum: this.getEnum('period') },
+            description: 'Hits per day, week, month or year',
           },
           {
             name: 'user',
diff --git a/services/jsdelivr/jsdelivr-hits-npm.service.js b/services/jsdelivr/jsdelivr-hits-npm.service.js
index 79db7f7f55..78bfa7e7b6 100644
--- a/services/jsdelivr/jsdelivr-hits-npm.service.js
+++ b/services/jsdelivr/jsdelivr-hits-npm.service.js
@@ -1,3 +1,4 @@
+import { pathParams } from '../index.js'
 import { schema, periodMap, BaseJsDelivrService } from './jsdelivr-base.js'
 
 export default class JsDelivrHitsNPM extends BaseJsDelivrService {
@@ -6,27 +7,46 @@ export default class JsDelivrHitsNPM extends BaseJsDelivrService {
     pattern: ':period(hd|hw|hm|hy)/:scope(@[^/]+)?/:packageName',
   }
 
-  static examples = [
-    {
-      title: 'jsDelivr hits (npm)',
-      pattern: ':period(hd|hw|hm|hy)/:packageName',
-      namedParams: {
-        period: 'hm',
-        packageName: 'jquery',
+  static openApi = {
+    '/jsdelivr/npm/{period}/{packageName}': {
+      get: {
+        summary: 'jsDelivr hits (npm)',
+        parameters: pathParams(
+          {
+            name: 'period',
+            schema: { type: 'string', enum: this.getEnum('period') },
+            example: 'hm',
+            description: 'Hits per day, week, month or year',
+          },
+          {
+            name: 'packageName',
+            example: 'fire',
+          },
+        ),
       },
-      staticPreview: this.render({ period: 'hm', hits: 920101789 }),
     },
-    {
-      title: 'jsDelivr hits (npm scoped)',
-      pattern: ':period(hd|hw|hm|hy)/:scope?/:packageName',
-      namedParams: {
-        period: 'hm',
-        scope: '@angular',
-        packageName: 'fire',
+    '/jsdelivr/npm/{period}/{scope}/{packageName}': {
+      get: {
+        summary: 'jsDelivr hits (npm scoped)',
+        parameters: pathParams(
+          {
+            name: 'period',
+            schema: { type: 'string', enum: this.getEnum('period') },
+            example: 'hm',
+            description: 'Hits per day, week, month or year',
+          },
+          {
+            name: 'scope',
+            example: '@angular',
+          },
+          {
+            name: 'packageName',
+            example: 'fire',
+          },
+        ),
       },
-      staticPreview: this.render({ period: 'hm', hits: 94123 }),
     },
-  ]
+  }
 
   async fetch({ period, packageName }) {
     return this._requestJson({
diff --git a/services/npms-io/npms-io-score.service.js b/services/npms-io/npms-io-score.service.js
index 6de07aa4dd..52f09c33f0 100644
--- a/services/npms-io/npms-io-score.service.js
+++ b/services/npms-io/npms-io-score.service.js
@@ -1,5 +1,5 @@
 import Joi from 'joi'
-import { BaseJsonService } from '../index.js'
+import { BaseJsonService, pathParams } from '../index.js'
 import { coveragePercentage } from '../color-formatters.js'
 
 // https://api-docs.npms.io/#api-Package-GetPackageInfo
@@ -15,7 +15,8 @@ const responseSchema = Joi.object({
   }),
 }).required()
 
-const keywords = ['node', 'npm score']
+const description =
+  '[npms.io](https://npms.io) holds statistics for javascript packages.'
 
 export default class NpmsIOScore extends BaseJsonService {
   static category = 'analysis'
@@ -26,37 +27,46 @@ export default class NpmsIOScore extends BaseJsonService {
       ':type(final-score|maintenance-score|popularity-score|quality-score)/:scope(@.+)?/:packageName',
   }
 
-  static examples = [
-    {
-      title: 'npms.io (final)',
-      namedParams: { type: 'final-score', packageName: 'egg' },
-      staticPreview: this.render({ score: 0.9711 }),
-      keywords,
-    },
-    {
-      title: 'npms.io (popularity)',
-      pattern: ':type/:scope/:packageName',
-      namedParams: {
-        type: 'popularity-score',
-        scope: '@vue',
-        packageName: 'cli',
+  static openApi = {
+    '/npms-io/{type}/{packageName}': {
+      get: {
+        summary: 'npms.io',
+        description,
+        parameters: pathParams(
+          {
+            name: 'type',
+            schema: { type: 'string', enum: this.getEnum('type') },
+            example: 'maintenance-score',
+          },
+          {
+            name: 'packageName',
+            example: 'command',
+          },
+        ),
       },
-      staticPreview: this.render({ type: 'popularity', score: 0.89 }),
-      keywords,
-    },
-    {
-      title: 'npms.io (quality)',
-      namedParams: { type: 'quality-score', packageName: 'egg' },
-      staticPreview: this.render({ type: 'quality', score: 0.98 }),
-      keywords,
     },
-    {
-      title: 'npms.io (maintenance)',
-      namedParams: { type: 'maintenance-score', packageName: 'command' },
-      staticPreview: this.render({ type: 'maintenance', score: 0.222 }),
-      keywords,
+    '/npms-io/{type}/{scope}/{packageName}': {
+      get: {
+        summary: 'npms.io (scoped package)',
+        description,
+        parameters: pathParams(
+          {
+            name: 'type',
+            schema: { type: 'string', enum: this.getEnum('type') },
+            example: 'maintenance-score',
+          },
+          {
+            name: 'scope',
+            example: '@vue',
+          },
+          {
+            name: 'packageName',
+            example: 'cli',
+          },
+        ),
+      },
     },
-  ]
+  }
 
   static defaultBadgeData = {
     label: 'score',
-- 
GitLab