Skip to content

Commit fa7cad4

Browse files
committed
refactor crate versions
1 parent 920b78f commit fa7cad4

5 files changed

+61
-27
lines changed

services/crates/crates-base.js

+40-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import Joi from 'joi'
22
import { nonNegativeInteger } from '../validators.js'
3-
import { BaseJsonService } from '../index.js'
3+
import { BaseJsonService, InvalidParameter } from '../index.js'
44

55
const keywords = ['Rust']
66

@@ -47,6 +47,45 @@ class BaseCratesService extends BaseJsonService {
4747
: `https://crates.io/api/v1/crates/${crate}?include=versions,downloads`
4848
return this._requestJson({ schema, url })
4949
}
50+
51+
/** get the default version for a crate using the same logic as crates.io
52+
* this should be kept in sync with the crates.io implementation in
53+
* https://github.com/rust-lang/crates.io/blob/20bbac9f5521cb4888ef63f8464fddb28fd973f5/app/models/crate.js#L34-L41
54+
*
55+
* @param {object} crate the `json.crate` response from crates.io
56+
* @returns {string} the default version string, or throws an error
57+
*/
58+
static defaultVersion(crate) {
59+
if (crate) {
60+
if (crate.max_stable_version) {
61+
return crate.max_stable_version
62+
}
63+
if (crate.max_version && crate.max_version !== '0.0.0') {
64+
return crate.max_version
65+
}
66+
}
67+
throw new InvalidParameter({
68+
prettyMessage:
69+
'default version not found, possibly all versions were yanked',
70+
})
71+
}
72+
73+
/** get the default version object from the `json.versions` array.
74+
*
75+
* @param {object} crate the `json.crate` response from crates.io
76+
* @param {object[]} versions the `json.versions` response from crates.io
77+
* @returns {object} the default version object, or throws an error if not found
78+
*/
79+
static defaultVersionObject(crate, versions) {
80+
const lastVerNum = BaseCratesService.defaultVersion(crate)
81+
const version = versions.find(ver => ver.num === lastVerNum)
82+
if (!version) {
83+
throw new InvalidParameter({
84+
prettyMessage: 'version object not found in the versions array',
85+
})
86+
}
87+
return version
88+
}
5089
}
5190

5291
export { BaseCratesService, keywords }

services/crates/crates-downloads.service.js

+6-8
Original file line numberDiff line numberDiff line change
@@ -68,16 +68,14 @@ export default class CratesDownloads extends BaseCratesService {
6868
transform({ variant, json }) {
6969
switch (variant) {
7070
case 'dv':
71-
let lastVer = json.version
7271
if (json.crate) {
73-
const lastVerNum = json.crate.max_stable_version
74-
? json.crate.max_stable_version
75-
: json.crate.max_version
76-
lastVer =
77-
json.versions.find(ver => ver.num === lastVerNum) ||
78-
json.versions[0]
72+
return BaseCratesService.defaultVersionObject(
73+
json.crate,
74+
json.versions,
75+
).downloads
76+
} else {
77+
return json.version.downloads
7978
}
80-
return lastVer.downloads
8179
case 'dr':
8280
return json.crate.recent_downloads || 0
8381
default:

services/crates/crates-license.service.js

+4-12
Original file line numberDiff line numberDiff line change
@@ -28,24 +28,16 @@ export default class CratesLicense extends BaseCratesService {
2828
return { message }
2929
}
3030

31-
static transform({ errors, version, versions, crate }) {
31+
static transform({ errors, version, crate, versions }) {
3232
// crates.io returns a 200 response with an errors object in
3333
// error scenarios, e.g. https://crates.io/api/v1/crates/libc/0.1
3434
if (errors) {
3535
throw new InvalidResponse({ prettyMessage: errors[0].detail })
3636
}
3737

38-
let license
39-
if (version) {
40-
license = version.license
41-
} else {
42-
const lastVerNum = crate.max_stable_version
43-
? crate.max_stable_version
44-
: crate.max_version
45-
const lastVer =
46-
versions.find(ver => ver.num === lastVerNum) || versions[0]
47-
license = lastVer.license
48-
}
38+
const license = version
39+
? version.license
40+
: BaseCratesService.defaultVersionObject(crate, versions).license
4941

5042
if (!license) {
5143
throw new InvalidResponse({ prettyMessage: 'invalid null license' })

services/crates/crates-license.spec.js

+10-3
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ import CratesLicense from './crates-license.service.js'
66
describe('CratesLicense', function () {
77
test(CratesLicense.transform, () => {
88
given({
9+
crate: { max_stable_version: '1.0.0', max_version: '1.0.0' },
910
version: { num: '1.0.0', license: 'MIT' },
10-
versions: [{ license: 'MIT/Apache 2.0' }],
11+
versions: [{ num: '1.0.0', license: 'MIT/Apache 2.0' }],
1112
}).expect({ license: 'MIT' })
1213
given({
13-
versions: [{ license: 'MIT/Apache 2.0' }],
14+
crate: { max_stable_version: '1.0.0', max_version: '1.0.0' },
15+
versions: [{ num: '1.0.0', license: 'MIT/Apache 2.0' }],
1416
}).expect({ license: 'MIT/Apache 2.0' })
1517
})
1618

@@ -31,7 +33,12 @@ describe('CratesLicense', function () {
3133
})
3234

3335
it('throws InvalidResponse on null license with latest version', function () {
34-
expect(() => CratesLicense.transform({ versions: [{ license: null }] }))
36+
expect(() =>
37+
CratesLicense.transform({
38+
crate: { max_stable_version: '1.0.0', max_version: '1.0.0' },
39+
versions: [{ num: '1.0.0', license: null }],
40+
}),
41+
)
3542
.to.throw(InvalidResponse)
3643
.with.property('prettyMessage', 'invalid null license')
3744
})

services/crates/crates-version.service.js

+1-3
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,7 @@ export default class CratesVersion extends BaseCratesService {
1919
if (json.errors) {
2020
throw new InvalidResponse({ prettyMessage: json.errors[0].detail })
2121
}
22-
return json.crate.max_stable_version
23-
? json.crate.max_stable_version
24-
: json.crate.max_version
22+
return BaseCratesService.defaultVersion(json.crate)
2523
}
2624

2725
async handle({ crate }) {

0 commit comments

Comments
 (0)