mirror of
https://github.com/badges/shields.git
synced 2025-04-18 19:44:04 +03:00
Add ability to format bytes as metric or IEC; affects [bundlejs bundlephobia ChromeWebStoreSize CratesSize DockerSize GithubRepoSize GithubCodeSize GithubSize NpmUnpackedSize SpigetDownloadSize steam VisualStudioAppCenterReleasesSize whatpulse] (#10547)
* add renderSizeBadge helper, use it everywhere - switch from pretty-bytes to byte-size - add renderSizeBadge() helper function - match upstream conventions for metric/IEC units - add new test helpers and use them in service tests * unrelated: fix npm unpacked size query param schema not strictly related to this PR but I noticed it was broken * chromewebstore: reformat size string, test against isIecFileSize
This commit is contained in:
parent
b7d7f4545d
commit
151c70dd17
21
package-lock.json
generated
21
package-lock.json
generated
@ -15,6 +15,7 @@
|
||||
"@shields_io/camp": "^18.1.2",
|
||||
"@xmldom/xmldom": "0.9.5",
|
||||
"badge-maker": "file:badge-maker",
|
||||
"byte-size": "^9.0.0",
|
||||
"bytes": "^3.1.2",
|
||||
"camelcase": "^8.0.0",
|
||||
"chalk": "^5.3.0",
|
||||
@ -45,7 +46,6 @@
|
||||
"parse-link-header": "^2.0.0",
|
||||
"path-to-regexp": "^6.3.0",
|
||||
"pg": "^8.13.1",
|
||||
"pretty-bytes": "^6.1.1",
|
||||
"priorityqueuejs": "^2.0.0",
|
||||
"prom-client": "^15.1.3",
|
||||
"qs": "^6.13.1",
|
||||
@ -8132,6 +8132,14 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/byte-size": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/byte-size/-/byte-size-9.0.0.tgz",
|
||||
"integrity": "sha512-xrJ8Hki7eQ6xew55mM6TG9zHI852OoAHcPfduWWtR6yxk2upTuIZy13VioRBDyHReHDdbeDPifUboeNkK/sXXA==",
|
||||
"engines": {
|
||||
"node": ">=12.17"
|
||||
}
|
||||
},
|
||||
"node_modules/bytes": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
|
||||
@ -24578,17 +24586,6 @@
|
||||
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/pretty-bytes": {
|
||||
"version": "6.1.1",
|
||||
"resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-6.1.1.tgz",
|
||||
"integrity": "sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==",
|
||||
"engines": {
|
||||
"node": "^14.13.1 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/pretty-error": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz",
|
||||
|
@ -27,6 +27,7 @@
|
||||
"@shields_io/camp": "^18.1.2",
|
||||
"@xmldom/xmldom": "0.9.5",
|
||||
"badge-maker": "file:badge-maker",
|
||||
"byte-size": "^9.0.0",
|
||||
"bytes": "^3.1.2",
|
||||
"camelcase": "^8.0.0",
|
||||
"chalk": "^5.3.0",
|
||||
@ -57,7 +58,6 @@
|
||||
"parse-link-header": "^2.0.0",
|
||||
"path-to-regexp": "^6.3.0",
|
||||
"pg": "^8.13.1",
|
||||
"pretty-bytes": "^6.1.1",
|
||||
"priorityqueuejs": "^2.0.0",
|
||||
"prom-client": "^15.1.3",
|
||||
"qs": "^6.13.1",
|
||||
|
@ -1,9 +1,11 @@
|
||||
import Joi from 'joi'
|
||||
import { BaseJsonService, pathParam, queryParam } from '../index.js'
|
||||
import { renderSizeBadge } from '../size.js'
|
||||
import { nonNegativeInteger } from '../validators.js'
|
||||
|
||||
const schema = Joi.object({
|
||||
size: Joi.object({
|
||||
compressedSize: Joi.string().required(),
|
||||
rawCompressedSize: nonNegativeInteger,
|
||||
}).required(),
|
||||
}).required()
|
||||
|
||||
@ -76,13 +78,6 @@ export default class BundlejsPackage extends BaseJsonService {
|
||||
|
||||
static defaultBadgeData = { label: 'bundlejs', color: 'informational' }
|
||||
|
||||
static render({ size }) {
|
||||
return {
|
||||
label: 'minified size (gzip)',
|
||||
message: size,
|
||||
}
|
||||
}
|
||||
|
||||
async fetch({ scope, packageName, exports }) {
|
||||
const searchParams = {
|
||||
q: `${scope ? `${scope}/` : ''}${packageName}`,
|
||||
@ -110,7 +105,7 @@ export default class BundlejsPackage extends BaseJsonService {
|
||||
|
||||
async handle({ scope, packageName }, { exports }) {
|
||||
const json = await this.fetch({ scope, packageName, exports })
|
||||
const size = json.size.compressedSize
|
||||
return this.constructor.render({ size })
|
||||
const size = json.size.rawCompressedSize
|
||||
return renderSizeBadge(size, 'metric', 'minified size (gzip)')
|
||||
}
|
||||
}
|
||||
|
@ -1,26 +1,26 @@
|
||||
import { isFileSize } from '../test-validators.js'
|
||||
import { isMetricFileSize } from '../test-validators.js'
|
||||
import { createServiceTester } from '../tester.js'
|
||||
export const t = await createServiceTester()
|
||||
|
||||
t.create('bundlejs/package (packageName)')
|
||||
.get('/jquery.json')
|
||||
.expectBadge({ label: 'minified size (gzip)', message: isFileSize })
|
||||
.expectBadge({ label: 'minified size (gzip)', message: isMetricFileSize })
|
||||
|
||||
t.create('bundlejs/package (version)')
|
||||
.get('/react@18.2.0.json')
|
||||
.expectBadge({ label: 'minified size (gzip)', message: isFileSize })
|
||||
.expectBadge({ label: 'minified size (gzip)', message: isMetricFileSize })
|
||||
|
||||
t.create('bundlejs/package (scoped)')
|
||||
.get('/@cycle/rx-run.json')
|
||||
.expectBadge({ label: 'minified size (gzip)', message: isFileSize })
|
||||
.expectBadge({ label: 'minified size (gzip)', message: isMetricFileSize })
|
||||
|
||||
t.create('bundlejs/package (select exports)')
|
||||
.get('/value-enhancer.json?exports=isVal,val')
|
||||
.expectBadge({ label: 'minified size (gzip)', message: isFileSize })
|
||||
.expectBadge({ label: 'minified size (gzip)', message: isMetricFileSize })
|
||||
|
||||
t.create('bundlejs/package (scoped version select exports)')
|
||||
.get('/@ngneat/falso@6.4.0.json?exports=randEmail,randFullName')
|
||||
.expectBadge({ label: 'minified size (gzip)', message: isFileSize })
|
||||
.expectBadge({ label: 'minified size (gzip)', message: isMetricFileSize })
|
||||
|
||||
t.create('bundlejs/package (not found)')
|
||||
.get('/react@18.2.0.json')
|
||||
|
@ -1,5 +1,5 @@
|
||||
import Joi from 'joi'
|
||||
import prettyBytes from 'pretty-bytes'
|
||||
import { renderSizeBadge } from '../size.js'
|
||||
import { nonNegativeInteger } from '../validators.js'
|
||||
import { BaseJsonService, pathParams } from '../index.js'
|
||||
|
||||
@ -112,10 +112,7 @@ export default class Bundlephobia extends BaseJsonService {
|
||||
|
||||
static render({ format, size }) {
|
||||
const label = format === 'min' ? 'minified size' : 'minzipped size'
|
||||
return {
|
||||
label,
|
||||
message: prettyBytes(size),
|
||||
}
|
||||
return renderSizeBadge(size, 'iec', label)
|
||||
}
|
||||
|
||||
async fetch({ scope, packageName, version }) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { isFileSize } from '../test-validators.js'
|
||||
import { isIecFileSize } from '../test-validators.js'
|
||||
import { createServiceTester } from '../tester.js'
|
||||
export const t = await createServiceTester()
|
||||
|
||||
@ -13,42 +13,42 @@ const data = [
|
||||
{
|
||||
format: formats.A,
|
||||
get: '/min/preact.json',
|
||||
expect: { label: 'minified size', message: isFileSize },
|
||||
expect: { label: 'minified size', message: isIecFileSize },
|
||||
},
|
||||
{
|
||||
format: formats.B,
|
||||
get: '/min/preact/8.0.0.json',
|
||||
expect: { label: 'minified size', message: isFileSize },
|
||||
expect: { label: 'minified size', message: isIecFileSize },
|
||||
},
|
||||
{
|
||||
format: formats.C,
|
||||
get: '/min/@cycle/core.json',
|
||||
expect: { label: 'minified size', message: isFileSize },
|
||||
expect: { label: 'minified size', message: isIecFileSize },
|
||||
},
|
||||
{
|
||||
format: formats.D,
|
||||
get: '/min/@cycle/core/7.0.0.json',
|
||||
expect: { label: 'minified size', message: isFileSize },
|
||||
expect: { label: 'minified size', message: isIecFileSize },
|
||||
},
|
||||
{
|
||||
format: formats.A,
|
||||
get: '/minzip/preact.json',
|
||||
expect: { label: 'minzipped size', message: isFileSize },
|
||||
expect: { label: 'minzipped size', message: isIecFileSize },
|
||||
},
|
||||
{
|
||||
format: formats.B,
|
||||
get: '/minzip/preact/8.0.0.json',
|
||||
expect: { label: 'minzipped size', message: isFileSize },
|
||||
expect: { label: 'minzipped size', message: isIecFileSize },
|
||||
},
|
||||
{
|
||||
format: formats.C,
|
||||
get: '/minzip/@cycle/core.json',
|
||||
expect: { label: 'minzipped size', message: isFileSize },
|
||||
expect: { label: 'minzipped size', message: isIecFileSize },
|
||||
},
|
||||
{
|
||||
format: formats.D,
|
||||
get: '/minzip/@cycle/core/7.0.0.json',
|
||||
expect: { label: 'minzipped size', message: isFileSize },
|
||||
expect: { label: 'minzipped size', message: isIecFileSize },
|
||||
},
|
||||
{
|
||||
format: formats.A,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { NotFound, pathParams } from '../index.js'
|
||||
import { InvalidResponse, NotFound, pathParams } from '../index.js'
|
||||
import BaseChromeWebStoreService from './chrome-web-store-base.js'
|
||||
|
||||
export default class ChromeWebStoreSize extends BaseChromeWebStoreService {
|
||||
@ -22,6 +22,17 @@ export default class ChromeWebStoreSize extends BaseChromeWebStoreService {
|
||||
color: 'blue',
|
||||
}
|
||||
|
||||
transform(sizeStr) {
|
||||
const match = sizeStr.match(/^(\d+)([a-zA-Z]+)$/)
|
||||
if (!match) {
|
||||
throw new InvalidResponse({
|
||||
prettyMessage: 'size does not match expected format',
|
||||
})
|
||||
}
|
||||
const [, size, units] = match
|
||||
return `${size} ${units}`
|
||||
}
|
||||
|
||||
async handle({ storeId }) {
|
||||
const chromeWebStore = await this.fetch({ storeId })
|
||||
const size = chromeWebStore.size()
|
||||
@ -30,6 +41,6 @@ export default class ChromeWebStoreSize extends BaseChromeWebStoreService {
|
||||
throw new NotFound({ prettyMessage: 'not found' })
|
||||
}
|
||||
|
||||
return { message: size }
|
||||
return { message: this.transform(size) }
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { createServiceTester } from '../tester.js'
|
||||
import { isIecFileSize } from '../test-validators.js'
|
||||
|
||||
export const t = await createServiceTester()
|
||||
const isFileSize = /^\d+(\.\d+)?(MiB|KiB)$/
|
||||
|
||||
t.create('Size').get('/nccfelhkfpbnefflolffkclhenplhiab.json').expectBadge({
|
||||
label: 'extension size',
|
||||
message: isFileSize,
|
||||
message: isIecFileSize,
|
||||
})
|
||||
|
||||
t.create('Size (not found)')
|
||||
|
@ -1,5 +1,5 @@
|
||||
import prettyBytes from 'pretty-bytes'
|
||||
import { pathParams } from '../index.js'
|
||||
import { renderSizeBadge } from '../size.js'
|
||||
import { BaseCratesService, description } from './crates-base.js'
|
||||
|
||||
export default class CratesSize extends BaseCratesService {
|
||||
@ -38,17 +38,9 @@ export default class CratesSize extends BaseCratesService {
|
||||
},
|
||||
}
|
||||
|
||||
render({ size }) {
|
||||
return {
|
||||
label: 'size',
|
||||
message: prettyBytes(size),
|
||||
color: 'blue',
|
||||
}
|
||||
}
|
||||
|
||||
async handle({ crate, version }) {
|
||||
const json = await this.fetch({ crate, version })
|
||||
const size = this.constructor.getVersionObj(json).crate_size
|
||||
return this.render({ size })
|
||||
return renderSizeBadge(size, 'iec')
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,14 @@
|
||||
import { createServiceTester } from '../tester.js'
|
||||
import { isFileSize } from '../test-validators.js'
|
||||
import { isIecFileSize } from '../test-validators.js'
|
||||
export const t = await createServiceTester()
|
||||
|
||||
t.create('size')
|
||||
.get('/tokio.json')
|
||||
.expectBadge({ label: 'size', message: isFileSize })
|
||||
.expectBadge({ label: 'size', message: isIecFileSize })
|
||||
|
||||
t.create('size (with version)')
|
||||
.get('/tokio/1.32.0.json')
|
||||
.expectBadge({ label: 'size', message: '725 kB' })
|
||||
.expectBadge({ label: 'size', message: '708 KiB' })
|
||||
|
||||
t.create('size (not found)')
|
||||
.get('/not-a-crate.json')
|
||||
|
@ -1,5 +1,5 @@
|
||||
import Joi from 'joi'
|
||||
import prettyBytes from 'pretty-bytes'
|
||||
import { renderSizeBadge } from '../size.js'
|
||||
import { nonNegativeInteger } from '../validators.js'
|
||||
import { latest } from '../version.js'
|
||||
import { BaseJsonService, NotFound, pathParams, queryParams } from '../index.js'
|
||||
@ -124,10 +124,6 @@ export default class DockerSize extends BaseJsonService {
|
||||
|
||||
static defaultBadgeData = { label: 'image size', color: 'blue' }
|
||||
|
||||
static render({ size }) {
|
||||
return { message: prettyBytes(size) }
|
||||
}
|
||||
|
||||
async fetch({ user, repo, tag, page }) {
|
||||
page = page ? `&page=${page}` : ''
|
||||
return await fetch(this, {
|
||||
@ -233,6 +229,6 @@ export default class DockerSize extends BaseJsonService {
|
||||
}
|
||||
|
||||
const { size } = await this.transform({ tag, sort, data, arch })
|
||||
return this.constructor.render({ size })
|
||||
return renderSizeBadge(size, 'iec', 'image size')
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { isFileSize } from '../test-validators.js'
|
||||
import { isIecFileSize } from '../test-validators.js'
|
||||
import { createServiceTester } from '../tester.js'
|
||||
export const t = await createServiceTester()
|
||||
|
||||
@ -6,35 +6,35 @@ t.create('docker image size (valid, library)')
|
||||
.get('/_/alpine.json')
|
||||
.expectBadge({
|
||||
label: 'image size',
|
||||
message: isFileSize,
|
||||
message: isIecFileSize,
|
||||
})
|
||||
|
||||
t.create('docker image size (valid, library, arch parameter )')
|
||||
.get('/_/mysql.json?arch=amd64')
|
||||
.expectBadge({
|
||||
label: 'image size',
|
||||
message: isFileSize,
|
||||
message: isIecFileSize,
|
||||
})
|
||||
|
||||
t.create('docker image size (valid, library with tag)')
|
||||
.get('/_/alpine/latest.json')
|
||||
.expectBadge({
|
||||
label: 'image size',
|
||||
message: isFileSize,
|
||||
message: isIecFileSize,
|
||||
})
|
||||
|
||||
t.create('docker image size (valid, user)')
|
||||
.get('/jrottenberg/ffmpeg.json')
|
||||
.expectBadge({
|
||||
label: 'image size',
|
||||
message: isFileSize,
|
||||
message: isIecFileSize,
|
||||
})
|
||||
|
||||
t.create('docker image size (valid, user with tag)')
|
||||
.get('/jrottenberg/ffmpeg/3.2-alpine.json')
|
||||
.expectBadge({
|
||||
label: 'image size',
|
||||
message: isFileSize,
|
||||
message: isIecFileSize,
|
||||
})
|
||||
|
||||
t.create('docker image size (invalid, incorrect tag)')
|
||||
|
@ -1,5 +1,5 @@
|
||||
import prettyBytes from 'pretty-bytes'
|
||||
import { pathParams } from '../index.js'
|
||||
import { renderSizeBadge } from '../size.js'
|
||||
import { BaseGithubLanguage } from './github-languages-base.js'
|
||||
import { documentation } from './github-helpers.js'
|
||||
|
||||
@ -31,15 +31,8 @@ export default class GithubCodeSize extends BaseGithubLanguage {
|
||||
|
||||
static defaultBadgeData = { label: 'code size' }
|
||||
|
||||
static render({ size }) {
|
||||
return {
|
||||
message: prettyBytes(size),
|
||||
color: 'blue',
|
||||
}
|
||||
}
|
||||
|
||||
async handle({ user, repo }) {
|
||||
const data = await this.fetch({ user, repo })
|
||||
return this.constructor.render({ size: this.getTotalSize(data) })
|
||||
return renderSizeBadge(this.getTotalSize(data), 'iec', 'code size')
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { isFileSize } from '../test-validators.js'
|
||||
import { isIecFileSize } from '../test-validators.js'
|
||||
import { createServiceTester } from '../tester.js'
|
||||
export const t = await createServiceTester()
|
||||
|
||||
@ -6,7 +6,7 @@ t.create('code size in bytes for all languages')
|
||||
.get('/badges/shields.json')
|
||||
.expectBadge({
|
||||
label: 'code size',
|
||||
message: isFileSize,
|
||||
message: isIecFileSize,
|
||||
})
|
||||
|
||||
t.create('code size in bytes for all languages (empty repo)')
|
||||
|
@ -1,6 +1,6 @@
|
||||
import Joi from 'joi'
|
||||
import prettyBytes from 'pretty-bytes'
|
||||
import { pathParams } from '../index.js'
|
||||
import { renderSizeBadge } from '../size.js'
|
||||
import { nonNegativeInteger } from '../validators.js'
|
||||
import { GithubAuthV3Service } from './github-auth-service.js'
|
||||
import { documentation, httpErrorsFor } from './github-helpers.js'
|
||||
@ -33,14 +33,6 @@ export default class GithubRepoSize extends GithubAuthV3Service {
|
||||
|
||||
static defaultBadgeData = { label: 'repo size' }
|
||||
|
||||
static render({ size }) {
|
||||
return {
|
||||
// note the GH API returns size in Kb
|
||||
message: prettyBytes(size * 1024),
|
||||
color: 'blue',
|
||||
}
|
||||
}
|
||||
|
||||
async fetch({ user, repo }) {
|
||||
return this._requestJson({
|
||||
url: `/repos/${user}/${repo}`,
|
||||
@ -51,6 +43,8 @@ export default class GithubRepoSize extends GithubAuthV3Service {
|
||||
|
||||
async handle({ user, repo }) {
|
||||
const { size } = await this.fetch({ user, repo })
|
||||
return this.constructor.render({ size })
|
||||
// note the GH API returns size in KiB
|
||||
// so we multiply by 1024 to get a size in bytes and then format that in IEC bytes
|
||||
return renderSizeBadge(size * 1024, 'iec', 'repo size')
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { isFileSize } from '../test-validators.js'
|
||||
import { isIecFileSize } from '../test-validators.js'
|
||||
import { createServiceTester } from '../tester.js'
|
||||
export const t = await createServiceTester()
|
||||
|
||||
t.create('repository size').get('/badges/shields.json').expectBadge({
|
||||
label: 'repo size',
|
||||
message: isFileSize,
|
||||
message: isIecFileSize,
|
||||
})
|
||||
|
||||
t.create('repository size (repo not found)')
|
||||
|
@ -1,5 +1,5 @@
|
||||
import Joi from 'joi'
|
||||
import prettyBytes from 'pretty-bytes'
|
||||
import { renderSizeBadge } from '../size.js'
|
||||
import { nonNegativeInteger } from '../validators.js'
|
||||
import { NotFound, pathParam, queryParam } from '../index.js'
|
||||
import { GithubAuthV3Service } from './github-auth-service.js'
|
||||
@ -44,13 +44,6 @@ export default class GithubSize extends GithubAuthV3Service {
|
||||
},
|
||||
}
|
||||
|
||||
static render({ size }) {
|
||||
return {
|
||||
message: prettyBytes(size),
|
||||
color: 'blue',
|
||||
}
|
||||
}
|
||||
|
||||
async fetch({ user, repo, path, branch }) {
|
||||
if (branch) {
|
||||
return this._requestJson({
|
||||
@ -73,6 +66,6 @@ export default class GithubSize extends GithubAuthV3Service {
|
||||
if (Array.isArray(body)) {
|
||||
throw new NotFound({ prettyMessage: 'not a regular file' })
|
||||
}
|
||||
return this.constructor.render({ size: body.size })
|
||||
return renderSizeBadge(body.size, 'iec')
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { isFileSize } from '../test-validators.js'
|
||||
import { isIecFileSize } from '../test-validators.js'
|
||||
import { createServiceTester } from '../tester.js'
|
||||
export const t = await createServiceTester()
|
||||
|
||||
t.create('File size')
|
||||
.get('/webcaetano/craft/build/phaser-craft.min.js.json')
|
||||
.expectBadge({ label: 'size', message: isFileSize })
|
||||
.expectBadge({ label: 'size', message: isIecFileSize })
|
||||
|
||||
t.create('File size 404')
|
||||
.get('/webcaetano/craft/build/does-not-exist.min.js.json')
|
||||
@ -20,12 +20,12 @@ t.create('File size for "not a regular file"')
|
||||
|
||||
t.create('File size for a specified branch')
|
||||
.get('/webcaetano/craft/build/craft.min.js.json?branch=version-2')
|
||||
.expectBadge({ label: 'size', message: isFileSize })
|
||||
.expectBadge({ label: 'size', message: isIecFileSize })
|
||||
|
||||
t.create('File size for a specified tag')
|
||||
.get('/webcaetano/craft/build/phaser-craft.min.js.json?branch=2.1.2')
|
||||
.expectBadge({ label: 'size', message: isFileSize })
|
||||
.expectBadge({ label: 'size', message: isIecFileSize })
|
||||
|
||||
t.create('File size for a specified commit')
|
||||
.get('/webcaetano/craft/build/phaser-craft.min.js.json?branch=b848dbb')
|
||||
.expectBadge({ label: 'size', message: isFileSize })
|
||||
.expectBadge({ label: 'size', message: isIecFileSize })
|
||||
|
@ -1,8 +1,11 @@
|
||||
import Joi from 'joi'
|
||||
import prettyBytes from 'pretty-bytes'
|
||||
import { pathParam, queryParam } from '../index.js'
|
||||
import { renderSizeBadge } from '../size.js'
|
||||
import { optionalNonNegativeInteger } from '../validators.js'
|
||||
import NpmBase, { packageNameDescription } from './npm-base.js'
|
||||
import NpmBase, {
|
||||
packageNameDescription,
|
||||
queryParamSchema,
|
||||
} from './npm-base.js'
|
||||
|
||||
const schema = Joi.object({
|
||||
dist: Joi.object({
|
||||
@ -16,6 +19,7 @@ export default class NpmUnpackedSize extends NpmBase {
|
||||
static route = {
|
||||
base: 'npm/unpacked-size',
|
||||
pattern: ':scope(@[^/]+)?/:packageName/:version*',
|
||||
queryParamSchema,
|
||||
}
|
||||
|
||||
static openApi = {
|
||||
@ -78,10 +82,13 @@ export default class NpmUnpackedSize extends NpmBase {
|
||||
})
|
||||
const { unpackedSize } = dist
|
||||
|
||||
if (unpackedSize) {
|
||||
return renderSizeBadge(unpackedSize, 'metric', 'unpacked size')
|
||||
}
|
||||
return {
|
||||
label: 'unpacked size',
|
||||
message: unpackedSize ? prettyBytes(unpackedSize) : 'unknown',
|
||||
color: unpackedSize ? 'blue' : 'lightgray',
|
||||
message: 'unknown',
|
||||
color: 'lightgray',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { isFileSize } from '../test-validators.js'
|
||||
import { isMetricFileSize } from '../test-validators.js'
|
||||
import { createServiceTester } from '../tester.js'
|
||||
|
||||
export const t = await createServiceTester()
|
||||
|
||||
t.create('Latest unpacked size')
|
||||
.get('/firereact.json')
|
||||
.expectBadge({ label: 'unpacked size', message: isFileSize })
|
||||
.expectBadge({ label: 'unpacked size', message: isMetricFileSize })
|
||||
|
||||
t.create('Nonexistent unpacked size with version')
|
||||
.get('/express/4.16.0.json')
|
||||
@ -13,15 +13,15 @@ t.create('Nonexistent unpacked size with version')
|
||||
|
||||
t.create('Unpacked size with version')
|
||||
.get('/firereact/0.7.0.json')
|
||||
.expectBadge({ label: 'unpacked size', message: '147 kB' })
|
||||
.expectBadge({ label: 'unpacked size', message: '147.2 kB' })
|
||||
|
||||
t.create('Unpacked size for scoped package')
|
||||
.get('/@testing-library/react.json')
|
||||
.expectBadge({ label: 'unpacked size', message: isFileSize })
|
||||
.expectBadge({ label: 'unpacked size', message: isMetricFileSize })
|
||||
|
||||
t.create('Unpacked size for scoped package with version')
|
||||
.get('/@testing-library/react/14.2.1.json')
|
||||
.expectBadge({ label: 'unpacked size', message: '5.41 MB' })
|
||||
.expectBadge({ label: 'unpacked size', message: '5.4 MB' })
|
||||
|
||||
t.create('Nonexistent unpacked size for scoped package with version')
|
||||
.get('/@cycle/rx-run/7.2.0.json')
|
||||
|
25
services/size.js
Normal file
25
services/size.js
Normal file
@ -0,0 +1,25 @@
|
||||
/**
|
||||
* @module
|
||||
*/
|
||||
|
||||
import byteSize from 'byte-size'
|
||||
|
||||
/**
|
||||
* Creates a badge object that displays information about a size in bytes number.
|
||||
* It should usually be used to output a size badge.
|
||||
*
|
||||
* @param {number} bytes - Raw number of bytes to be formatted
|
||||
* @param {'metric'|'iec'} units - Either 'metric' (multiples of 1000) or 'iec' (multiples of 1024).
|
||||
* This should align with how the upstream displays sizes.
|
||||
* @param {string} [label='size'] - Custom label
|
||||
* @returns {object} A badge object that has three properties: label, message, and color
|
||||
*/
|
||||
function renderSizeBadge(bytes, units, label = 'size') {
|
||||
return {
|
||||
label,
|
||||
message: byteSize(bytes, { units }).toString(),
|
||||
color: 'blue',
|
||||
}
|
||||
}
|
||||
|
||||
export { renderSizeBadge }
|
@ -1,10 +1,10 @@
|
||||
import { isFileSize } from '../test-validators.js'
|
||||
import { isMetricFileSize } from '../test-validators.js'
|
||||
import { createServiceTester } from '../tester.js'
|
||||
export const t = await createServiceTester()
|
||||
|
||||
t.create('EssentialsX (hosted resource)')
|
||||
.get('/771.json')
|
||||
.expectBadge({ label: 'size', message: isFileSize })
|
||||
.expectBadge({ label: 'size', message: isMetricFileSize })
|
||||
|
||||
t.create('external resource').get('/9089.json').expectBadge({
|
||||
label: 'size',
|
||||
|
@ -1,6 +1,6 @@
|
||||
import Joi from 'joi'
|
||||
import prettyBytes from 'pretty-bytes'
|
||||
import { renderDateBadge } from '../date.js'
|
||||
import { renderSizeBadge } from '../size.js'
|
||||
import { renderDownloadsBadge } from '../downloads.js'
|
||||
import { metric } from '../text-formatters.js'
|
||||
import { NotFound, pathParams } from '../index.js'
|
||||
@ -208,12 +208,8 @@ class SteamFileSize extends SteamFileService {
|
||||
label: 'size',
|
||||
}
|
||||
|
||||
static render({ fileSize }) {
|
||||
return { message: prettyBytes(fileSize), color: 'informational' }
|
||||
}
|
||||
|
||||
async onRequest({ response }) {
|
||||
return this.constructor.render({ fileSize: response.file_size })
|
||||
return renderSizeBadge(response.file_size, 'metric')
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,9 @@
|
||||
import { ServiceTester } from '../tester.js'
|
||||
import { isMetric, isFileSize, isFormattedDate } from '../test-validators.js'
|
||||
import {
|
||||
isMetric,
|
||||
isMetricFileSize,
|
||||
isFormattedDate,
|
||||
} from '../test-validators.js'
|
||||
|
||||
export const t = new ServiceTester({
|
||||
id: 'steam',
|
||||
@ -12,7 +16,7 @@ t.create('Collection Files')
|
||||
|
||||
t.create('File Size')
|
||||
.get('/size/1523924535.json')
|
||||
.expectBadge({ label: 'size', message: isFileSize })
|
||||
.expectBadge({ label: 'size', message: isMetricFileSize })
|
||||
|
||||
t.create('Release Date')
|
||||
.get('/release-date/1523924535.json')
|
||||
|
@ -106,9 +106,12 @@ const isPercentage = Joi.alternatives().try(
|
||||
isDecimalPercentageNegative,
|
||||
)
|
||||
|
||||
const isFileSize = withRegex(
|
||||
const isMetricFileSize = withRegex(
|
||||
/^[0-9]*[.]?[0-9]+\s(B|kB|KB|MB|GB|TB|PB|EB|ZB|YB)$/,
|
||||
)
|
||||
const isIecFileSize = withRegex(
|
||||
/^[0-9]*[.]?[0-9]+\s(B|KiB|MiB|GiB|TiB|PiB|EiB|ZiB|YiB)$/,
|
||||
)
|
||||
|
||||
const isFormattedDate = Joi.alternatives().try(
|
||||
Joi.equal('today', 'yesterday'),
|
||||
@ -202,7 +205,8 @@ export {
|
||||
isPercentage,
|
||||
isIntegerPercentage,
|
||||
isDecimalPercentage,
|
||||
isFileSize,
|
||||
isMetricFileSize,
|
||||
isIecFileSize,
|
||||
isFormattedDate,
|
||||
isRelativeFormattedDate,
|
||||
isDependencyState,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import Joi from 'joi'
|
||||
import prettyBytes from 'pretty-bytes'
|
||||
import { pathParams } from '../index.js'
|
||||
import { renderSizeBadge } from '../size.js'
|
||||
import { nonNegativeInteger } from '../validators.js'
|
||||
import {
|
||||
BaseVisualStudioAppCenterService,
|
||||
@ -47,14 +47,8 @@ export default class VisualStudioAppCenterReleasesSize extends BaseVisualStudioA
|
||||
color: 'blue',
|
||||
}
|
||||
|
||||
static render({ size }) {
|
||||
return {
|
||||
message: prettyBytes(size),
|
||||
}
|
||||
}
|
||||
|
||||
async handle({ owner, app, token }) {
|
||||
const { size } = await this.fetch({ owner, app, token, schema })
|
||||
return this.constructor.render({ size })
|
||||
return renderSizeBadge(size, 'metric')
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { createServiceTester } from '../tester.js'
|
||||
import { isFileSize } from '../test-validators.js'
|
||||
import { isMetricFileSize } from '../test-validators.js'
|
||||
export const t = await createServiceTester()
|
||||
|
||||
t.create('8368844 bytes to 8.37 megabytes')
|
||||
@ -13,7 +13,7 @@ t.create('8368844 bytes to 8.37 megabytes')
|
||||
)
|
||||
.expectBadge({
|
||||
label: 'size',
|
||||
message: '8.37 MB',
|
||||
message: '8.4 MB',
|
||||
})
|
||||
|
||||
t.create('Valid Release')
|
||||
@ -22,7 +22,7 @@ t.create('Valid Release')
|
||||
)
|
||||
.expectBadge({
|
||||
label: 'size',
|
||||
message: isFileSize,
|
||||
message: isMetricFileSize,
|
||||
})
|
||||
|
||||
t.create('Valid user, invalid project, valid API token')
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { createServiceTester } from '../tester.js'
|
||||
import {
|
||||
isFileSize,
|
||||
isMetricFileSize,
|
||||
isHumanized,
|
||||
isMetric,
|
||||
isOrdinalNumber,
|
||||
@ -21,11 +21,11 @@ t.create('WhatPulse team as team id, clicks')
|
||||
|
||||
t.create('WhatPulse team as team id, download')
|
||||
.get('/download/team/1295.json')
|
||||
.expectBadge({ label: 'download', message: isFileSize })
|
||||
.expectBadge({ label: 'download', message: isMetricFileSize })
|
||||
|
||||
t.create('WhatPulse team as team id, upload')
|
||||
.get('/upload/team/1295.json')
|
||||
.expectBadge({ label: 'upload', message: isFileSize })
|
||||
.expectBadge({ label: 'upload', message: isMetricFileSize })
|
||||
|
||||
t.create('WhatPulse team as team name, keys - from Ranks')
|
||||
.get('/keys/team/dutch power cows.json?rank')
|
||||
|
Loading…
x
Reference in New Issue
Block a user