Add [npm] type definitions badge (#1541)
Let a package show off its type definitions based on devDependency data in the published npm package. Close #1252
This commit is contained in:
@@ -840,6 +840,15 @@ const allBadgeExamples = [
|
||||
'node'
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'npm type definitions',
|
||||
previewUri: '/npm/types/chalk.svg',
|
||||
keywords: [
|
||||
'node',
|
||||
'typescript',
|
||||
'flow'
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'PyPI',
|
||||
previewUri: '/pypi/v/nine.svg',
|
||||
|
||||
@@ -1,7 +1,46 @@
|
||||
'use strict';
|
||||
|
||||
const { rangeStart, minor } = require('./version');
|
||||
|
||||
const defaultNpmRegistryUri = 'https://registry.npmjs.org';
|
||||
|
||||
function makePackageDataUrl({ registryUrl, scope, packageName }) {
|
||||
registryUrl = registryUrl || defaultNpmRegistryUri;
|
||||
if (scope === undefined) {
|
||||
// e.g. https://registry.npmjs.org/express/latest
|
||||
// Use this endpoint as an optimization. It covers the vast majority of
|
||||
// these badges, and the response is smaller.
|
||||
return `${registryUrl}/${packageName}/latest`;
|
||||
} else {
|
||||
// e.g. https://registry.npmjs.org/@cedx%2Fgulp-david
|
||||
// because https://registry.npmjs.org/@cedx%2Fgulp-david/latest does not work
|
||||
const path = encodeURIComponent(`${scope}/${packageName}`);
|
||||
return `${registryUrl}/@${path}`;
|
||||
}
|
||||
}
|
||||
|
||||
function typeDefinitions(packageData) {
|
||||
const { devDependencies } = packageData;
|
||||
|
||||
const supportedLanguages = [
|
||||
{ name: 'TypeScript', range: devDependencies.typescript },
|
||||
{ name: 'Flow', range: devDependencies['flow-bin'] },
|
||||
]
|
||||
.filter(lang => lang.range !== undefined)
|
||||
.map(({ name, range }) => {
|
||||
const version = minor(rangeStart(range));
|
||||
return `${name} v${version}`;
|
||||
});
|
||||
|
||||
if (supportedLanguages.length > 0) {
|
||||
return supportedLanguages.join(' | ');
|
||||
} else {
|
||||
return 'none';
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
defaultNpmRegistryUri,
|
||||
makePackageDataUrl,
|
||||
typeDefinitions,
|
||||
};
|
||||
|
||||
10
lib/npm-badge-helpers.spec.js
Normal file
10
lib/npm-badge-helpers.spec.js
Normal file
@@ -0,0 +1,10 @@
|
||||
'use strict';
|
||||
|
||||
const { test, given } = require('sazerac');
|
||||
const { typeDefinitions } = require('./npm-badge-helpers');
|
||||
|
||||
describe('NPM badge helpers', function () {
|
||||
test(typeDefinitions, () => {
|
||||
given({ devDependencies: { typescript: '^2.4.7' } }).expect('TypeScript v2.4');
|
||||
});
|
||||
});
|
||||
@@ -28,7 +28,6 @@ function latest(versions) {
|
||||
}
|
||||
return version;
|
||||
}
|
||||
exports.latest = latest;
|
||||
|
||||
function listCompare(a, b) {
|
||||
const alen = a.length, blen = b.length;
|
||||
@@ -41,7 +40,6 @@ function listCompare(a, b) {
|
||||
}
|
||||
return alen - blen;
|
||||
}
|
||||
exports.listCompare = listCompare;
|
||||
|
||||
// === Private helper functions ===
|
||||
|
||||
@@ -81,3 +79,50 @@ function compareDottedVersion(v1, v2) {
|
||||
}
|
||||
return v1 < v2? -1: v1 > v2? 1: 0;
|
||||
}
|
||||
|
||||
// Slice the specified number of dotted parts from the given semver version.
|
||||
// e.g. slice('2.4.7', 'minor') -> '2.4'
|
||||
function slice(v, releaseType) {
|
||||
if (! semver.valid(v)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const major = semver.major(v);
|
||||
const minor = semver.minor(v);
|
||||
const patch = semver.patch(v);
|
||||
const prerelease = semver.prerelease(v);
|
||||
|
||||
const dottedParts = {
|
||||
major: [major],
|
||||
minor: [major, minor],
|
||||
patch: [major, minor, patch],
|
||||
}[releaseType];
|
||||
|
||||
if (dottedParts === undefined) {
|
||||
throw Error(`Unknown releaseType: ${releaseType}`);
|
||||
}
|
||||
|
||||
const dotted = dottedParts.join('.');
|
||||
if (prerelease) {
|
||||
return `${dotted}-${prerelease.join('.')}`;
|
||||
} else {
|
||||
return dotted;
|
||||
}
|
||||
}
|
||||
|
||||
function minor(v) {
|
||||
return slice(v, 'minor');
|
||||
}
|
||||
|
||||
function rangeStart(v) {
|
||||
const range = new semver.Range(v);
|
||||
return range.set[0][0].semver.version;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
latest,
|
||||
listCompare,
|
||||
slice,
|
||||
minor,
|
||||
rangeStart,
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
const { test, given } = require('sazerac');
|
||||
const {latest} = require('./version');
|
||||
const { latest, slice, rangeStart } = require('./version');
|
||||
|
||||
describe('Version helpers', function () {
|
||||
test(latest, () => {
|
||||
@@ -31,4 +31,17 @@ describe('Version helpers', function () {
|
||||
// Simple (one-number) versions
|
||||
given(['2', '10', '1']).expect('10');
|
||||
});
|
||||
|
||||
test(slice, () => {
|
||||
given('2.4.7', 'major').expect('2');
|
||||
given('2.4.7', 'minor').expect('2.4');
|
||||
given('2.4.7', 'patch').expect('2.4.7');
|
||||
given('2.4.7-alpha.1', 'major').expect('2-alpha.1');
|
||||
given('2.4.7-alpha.1', 'minor').expect('2.4-alpha.1');
|
||||
given('2.4.7-alpha.1', 'patch').expect('2.4.7-alpha.1');
|
||||
});
|
||||
|
||||
test(rangeStart, () => {
|
||||
given('^2.4.7').expect('2.4.7');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user