Skip to content

Commit 151c70d

Browse files
authored
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
1 parent b7d7f45 commit 151c70d

28 files changed

+142
-144
lines changed

Diff for: package-lock.json

+9-12
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"@shields_io/camp": "^18.1.2",
2828
"@xmldom/xmldom": "0.9.5",
2929
"badge-maker": "file:badge-maker",
30+
"byte-size": "^9.0.0",
3031
"bytes": "^3.1.2",
3132
"camelcase": "^8.0.0",
3233
"chalk": "^5.3.0",
@@ -57,7 +58,6 @@
5758
"parse-link-header": "^2.0.0",
5859
"path-to-regexp": "^6.3.0",
5960
"pg": "^8.13.1",
60-
"pretty-bytes": "^6.1.1",
6161
"priorityqueuejs": "^2.0.0",
6262
"prom-client": "^15.1.3",
6363
"qs": "^6.13.1",

Diff for: services/bundlejs/bundlejs-package.service.js

+5-10
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import Joi from 'joi'
22
import { BaseJsonService, pathParam, queryParam } from '../index.js'
3+
import { renderSizeBadge } from '../size.js'
4+
import { nonNegativeInteger } from '../validators.js'
35

46
const schema = Joi.object({
57
size: Joi.object({
6-
compressedSize: Joi.string().required(),
8+
rawCompressedSize: nonNegativeInteger,
79
}).required(),
810
}).required()
911

@@ -76,13 +78,6 @@ export default class BundlejsPackage extends BaseJsonService {
7678

7779
static defaultBadgeData = { label: 'bundlejs', color: 'informational' }
7880

79-
static render({ size }) {
80-
return {
81-
label: 'minified size (gzip)',
82-
message: size,
83-
}
84-
}
85-
8681
async fetch({ scope, packageName, exports }) {
8782
const searchParams = {
8883
q: `${scope ? `${scope}/` : ''}${packageName}`,
@@ -110,7 +105,7 @@ export default class BundlejsPackage extends BaseJsonService {
110105

111106
async handle({ scope, packageName }, { exports }) {
112107
const json = await this.fetch({ scope, packageName, exports })
113-
const size = json.size.compressedSize
114-
return this.constructor.render({ size })
108+
const size = json.size.rawCompressedSize
109+
return renderSizeBadge(size, 'metric', 'minified size (gzip)')
115110
}
116111
}

Diff for: services/bundlejs/bundlejs-package.tester.js

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,26 @@
1-
import { isFileSize } from '../test-validators.js'
1+
import { isMetricFileSize } from '../test-validators.js'
22
import { createServiceTester } from '../tester.js'
33
export const t = await createServiceTester()
44

55
t.create('bundlejs/package (packageName)')
66
.get('/jquery.json')
7-
.expectBadge({ label: 'minified size (gzip)', message: isFileSize })
7+
.expectBadge({ label: 'minified size (gzip)', message: isMetricFileSize })
88

99
t.create('bundlejs/package (version)')
1010
.get('/react@18.2.0.json')
11-
.expectBadge({ label: 'minified size (gzip)', message: isFileSize })
11+
.expectBadge({ label: 'minified size (gzip)', message: isMetricFileSize })
1212

1313
t.create('bundlejs/package (scoped)')
1414
.get('/@cycle/rx-run.json')
15-
.expectBadge({ label: 'minified size (gzip)', message: isFileSize })
15+
.expectBadge({ label: 'minified size (gzip)', message: isMetricFileSize })
1616

1717
t.create('bundlejs/package (select exports)')
1818
.get('/value-enhancer.json?exports=isVal,val')
19-
.expectBadge({ label: 'minified size (gzip)', message: isFileSize })
19+
.expectBadge({ label: 'minified size (gzip)', message: isMetricFileSize })
2020

2121
t.create('bundlejs/package (scoped version select exports)')
2222
.get('/@ngneat/falso@6.4.0.json?exports=randEmail,randFullName')
23-
.expectBadge({ label: 'minified size (gzip)', message: isFileSize })
23+
.expectBadge({ label: 'minified size (gzip)', message: isMetricFileSize })
2424

2525
t.create('bundlejs/package (not found)')
2626
.get('/react@18.2.0.json')

Diff for: services/bundlephobia/bundlephobia.service.js

+2-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import Joi from 'joi'
2-
import prettyBytes from 'pretty-bytes'
2+
import { renderSizeBadge } from '../size.js'
33
import { nonNegativeInteger } from '../validators.js'
44
import { BaseJsonService, pathParams } from '../index.js'
55

@@ -112,10 +112,7 @@ export default class Bundlephobia extends BaseJsonService {
112112

113113
static render({ format, size }) {
114114
const label = format === 'min' ? 'minified size' : 'minzipped size'
115-
return {
116-
label,
117-
message: prettyBytes(size),
118-
}
115+
return renderSizeBadge(size, 'iec', label)
119116
}
120117

121118
async fetch({ scope, packageName, version }) {

Diff for: services/bundlephobia/bundlephobia.tester.js

+9-9
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { isFileSize } from '../test-validators.js'
1+
import { isIecFileSize } from '../test-validators.js'
22
import { createServiceTester } from '../tester.js'
33
export const t = await createServiceTester()
44

@@ -13,42 +13,42 @@ const data = [
1313
{
1414
format: formats.A,
1515
get: '/min/preact.json',
16-
expect: { label: 'minified size', message: isFileSize },
16+
expect: { label: 'minified size', message: isIecFileSize },
1717
},
1818
{
1919
format: formats.B,
2020
get: '/min/preact/8.0.0.json',
21-
expect: { label: 'minified size', message: isFileSize },
21+
expect: { label: 'minified size', message: isIecFileSize },
2222
},
2323
{
2424
format: formats.C,
2525
get: '/min/@cycle/core.json',
26-
expect: { label: 'minified size', message: isFileSize },
26+
expect: { label: 'minified size', message: isIecFileSize },
2727
},
2828
{
2929
format: formats.D,
3030
get: '/min/@cycle/core/7.0.0.json',
31-
expect: { label: 'minified size', message: isFileSize },
31+
expect: { label: 'minified size', message: isIecFileSize },
3232
},
3333
{
3434
format: formats.A,
3535
get: '/minzip/preact.json',
36-
expect: { label: 'minzipped size', message: isFileSize },
36+
expect: { label: 'minzipped size', message: isIecFileSize },
3737
},
3838
{
3939
format: formats.B,
4040
get: '/minzip/preact/8.0.0.json',
41-
expect: { label: 'minzipped size', message: isFileSize },
41+
expect: { label: 'minzipped size', message: isIecFileSize },
4242
},
4343
{
4444
format: formats.C,
4545
get: '/minzip/@cycle/core.json',
46-
expect: { label: 'minzipped size', message: isFileSize },
46+
expect: { label: 'minzipped size', message: isIecFileSize },
4747
},
4848
{
4949
format: formats.D,
5050
get: '/minzip/@cycle/core/7.0.0.json',
51-
expect: { label: 'minzipped size', message: isFileSize },
51+
expect: { label: 'minzipped size', message: isIecFileSize },
5252
},
5353
{
5454
format: formats.A,

Diff for: services/chrome-web-store/chrome-web-store-size.service.js

+13-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { NotFound, pathParams } from '../index.js'
1+
import { InvalidResponse, NotFound, pathParams } from '../index.js'
22
import BaseChromeWebStoreService from './chrome-web-store-base.js'
33

44
export default class ChromeWebStoreSize extends BaseChromeWebStoreService {
@@ -22,6 +22,17 @@ export default class ChromeWebStoreSize extends BaseChromeWebStoreService {
2222
color: 'blue',
2323
}
2424

25+
transform(sizeStr) {
26+
const match = sizeStr.match(/^(\d+)([a-zA-Z]+)$/)
27+
if (!match) {
28+
throw new InvalidResponse({
29+
prettyMessage: 'size does not match expected format',
30+
})
31+
}
32+
const [, size, units] = match
33+
return `${size} ${units}`
34+
}
35+
2536
async handle({ storeId }) {
2637
const chromeWebStore = await this.fetch({ storeId })
2738
const size = chromeWebStore.size()
@@ -30,6 +41,6 @@ export default class ChromeWebStoreSize extends BaseChromeWebStoreService {
3041
throw new NotFound({ prettyMessage: 'not found' })
3142
}
3243

33-
return { message: size }
44+
return { message: this.transform(size) }
3445
}
3546
}

Diff for: services/chrome-web-store/chrome-web-store-size.tester.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { createServiceTester } from '../tester.js'
2+
import { isIecFileSize } from '../test-validators.js'
23

34
export const t = await createServiceTester()
4-
const isFileSize = /^\d+(\.\d+)?(MiB|KiB)$/
55

66
t.create('Size').get('/nccfelhkfpbnefflolffkclhenplhiab.json').expectBadge({
77
label: 'extension size',
8-
message: isFileSize,
8+
message: isIecFileSize,
99
})
1010

1111
t.create('Size (not found)')

Diff for: services/crates/crates-size.service.js

+2-10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import prettyBytes from 'pretty-bytes'
21
import { pathParams } from '../index.js'
2+
import { renderSizeBadge } from '../size.js'
33
import { BaseCratesService, description } from './crates-base.js'
44

55
export default class CratesSize extends BaseCratesService {
@@ -38,17 +38,9 @@ export default class CratesSize extends BaseCratesService {
3838
},
3939
}
4040

41-
render({ size }) {
42-
return {
43-
label: 'size',
44-
message: prettyBytes(size),
45-
color: 'blue',
46-
}
47-
}
48-
4941
async handle({ crate, version }) {
5042
const json = await this.fetch({ crate, version })
5143
const size = this.constructor.getVersionObj(json).crate_size
52-
return this.render({ size })
44+
return renderSizeBadge(size, 'iec')
5345
}
5446
}

Diff for: services/crates/crates-size.tester.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import { createServiceTester } from '../tester.js'
2-
import { isFileSize } from '../test-validators.js'
2+
import { isIecFileSize } from '../test-validators.js'
33
export const t = await createServiceTester()
44

55
t.create('size')
66
.get('/tokio.json')
7-
.expectBadge({ label: 'size', message: isFileSize })
7+
.expectBadge({ label: 'size', message: isIecFileSize })
88

99
t.create('size (with version)')
1010
.get('/tokio/1.32.0.json')
11-
.expectBadge({ label: 'size', message: '725 kB' })
11+
.expectBadge({ label: 'size', message: '708 KiB' })
1212

1313
t.create('size (not found)')
1414
.get('/not-a-crate.json')

Diff for: services/docker/docker-size.service.js

+2-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import Joi from 'joi'
2-
import prettyBytes from 'pretty-bytes'
2+
import { renderSizeBadge } from '../size.js'
33
import { nonNegativeInteger } from '../validators.js'
44
import { latest } from '../version.js'
55
import { BaseJsonService, NotFound, pathParams, queryParams } from '../index.js'
@@ -124,10 +124,6 @@ export default class DockerSize extends BaseJsonService {
124124

125125
static defaultBadgeData = { label: 'image size', color: 'blue' }
126126

127-
static render({ size }) {
128-
return { message: prettyBytes(size) }
129-
}
130-
131127
async fetch({ user, repo, tag, page }) {
132128
page = page ? `&page=${page}` : ''
133129
return await fetch(this, {
@@ -233,6 +229,6 @@ export default class DockerSize extends BaseJsonService {
233229
}
234230

235231
const { size } = await this.transform({ tag, sort, data, arch })
236-
return this.constructor.render({ size })
232+
return renderSizeBadge(size, 'iec', 'image size')
237233
}
238234
}

Diff for: services/docker/docker-size.tester.js

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,40 @@
1-
import { isFileSize } from '../test-validators.js'
1+
import { isIecFileSize } from '../test-validators.js'
22
import { createServiceTester } from '../tester.js'
33
export const t = await createServiceTester()
44

55
t.create('docker image size (valid, library)')
66
.get('/_/alpine.json')
77
.expectBadge({
88
label: 'image size',
9-
message: isFileSize,
9+
message: isIecFileSize,
1010
})
1111

1212
t.create('docker image size (valid, library, arch parameter )')
1313
.get('/_/mysql.json?arch=amd64')
1414
.expectBadge({
1515
label: 'image size',
16-
message: isFileSize,
16+
message: isIecFileSize,
1717
})
1818

1919
t.create('docker image size (valid, library with tag)')
2020
.get('/_/alpine/latest.json')
2121
.expectBadge({
2222
label: 'image size',
23-
message: isFileSize,
23+
message: isIecFileSize,
2424
})
2525

2626
t.create('docker image size (valid, user)')
2727
.get('/jrottenberg/ffmpeg.json')
2828
.expectBadge({
2929
label: 'image size',
30-
message: isFileSize,
30+
message: isIecFileSize,
3131
})
3232

3333
t.create('docker image size (valid, user with tag)')
3434
.get('/jrottenberg/ffmpeg/3.2-alpine.json')
3535
.expectBadge({
3636
label: 'image size',
37-
message: isFileSize,
37+
message: isIecFileSize,
3838
})
3939

4040
t.create('docker image size (invalid, incorrect tag)')

Diff for: services/github/github-code-size.service.js

+2-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import prettyBytes from 'pretty-bytes'
21
import { pathParams } from '../index.js'
2+
import { renderSizeBadge } from '../size.js'
33
import { BaseGithubLanguage } from './github-languages-base.js'
44
import { documentation } from './github-helpers.js'
55

@@ -31,15 +31,8 @@ export default class GithubCodeSize extends BaseGithubLanguage {
3131

3232
static defaultBadgeData = { label: 'code size' }
3333

34-
static render({ size }) {
35-
return {
36-
message: prettyBytes(size),
37-
color: 'blue',
38-
}
39-
}
40-
4134
async handle({ user, repo }) {
4235
const data = await this.fetch({ user, repo })
43-
return this.constructor.render({ size: this.getTotalSize(data) })
36+
return renderSizeBadge(this.getTotalSize(data), 'iec', 'code size')
4437
}
4538
}

0 commit comments

Comments
 (0)