kopia lustrzana https://github.com/badgen/badgen.net
refactor: standardize external SVG badge parsing (#493)
* refactor(codacy): standardize svg parsing * refactor(melpa): standardize svg parsing * refactor(synk): standardize svg parsing * refactor: introduce `is-badge` helperpull/496/head^2
rodzic
dad2a6ff56
commit
9ad05785d2
|
@ -1,5 +1,5 @@
|
|||
import got from '../libs/got'
|
||||
import { coverage as cov, coverageColor } from '../libs/utils'
|
||||
import { isBadge, coverage as cov, coverageColor } from '../libs/utils'
|
||||
import { createBadgenHandler, PathArgs } from '../libs/create-badgen-handler'
|
||||
|
||||
const CODACY_API_URL = 'https://api.codacy.com/'
|
||||
|
@ -38,35 +38,37 @@ async function handler ({ type, projectId, branch }: PathArgs) {
|
|||
const searchParams = new URLSearchParams()
|
||||
if (branch) searchParams.append('branch', branch)
|
||||
const endpoint = `project/badge/${type}/${projectId}`
|
||||
const svg = await client.get(endpoint, { searchParams }).text()
|
||||
|
||||
const subject = SUBJECT_BY_TYPE[type] || 'codacy'
|
||||
const status = svg.match(/\/>\s*<text.*?>([^<]+)<\//i)?.[1].trim() ?? ''
|
||||
const resp = await client.get(endpoint, { searchParams })
|
||||
const params = isBadge(resp) && parseBadge(resp.body, type)
|
||||
return params || {
|
||||
subject: 'codacy',
|
||||
status: 'unknown',
|
||||
color: 'grey'
|
||||
}
|
||||
}
|
||||
|
||||
function parseBadge(svg: string, type: string) {
|
||||
const subject = SUBJECT_BY_TYPE[type]
|
||||
switch (type) {
|
||||
case 'coverage': {
|
||||
const status = svg.match(/text-anchor=[^>]*?>([^<]+)<\//i)?.[1].trim() ?? ''
|
||||
const percentage = parseFloat(status)
|
||||
if (Number.isNaN(percentage)) break
|
||||
if (Number.isNaN(percentage)) return
|
||||
return {
|
||||
subject,
|
||||
subject: subject || 'codacy',
|
||||
status: cov(percentage),
|
||||
color: coverageColor(percentage)
|
||||
}
|
||||
}
|
||||
case 'grade': {
|
||||
const status = svg.match(/visibility=[^>]*?>([^<]+)<\//i)?.[1].trim() ?? ''
|
||||
const color = COLORS_BY_GRADE[status]
|
||||
if (!color) break
|
||||
if (!status || !color) return
|
||||
return {
|
||||
subject,
|
||||
subject: subject || 'codacy',
|
||||
status,
|
||||
color
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
subject,
|
||||
status: 'invalid',
|
||||
color: 'grey'
|
||||
}
|
||||
}
|
||||
|
|
21
api/melpa.ts
21
api/melpa.ts
|
@ -1,5 +1,5 @@
|
|||
import got from '../libs/got'
|
||||
import { version, versionColor } from '../libs/utils'
|
||||
import { isBadge, version, versionColor } from '../libs/utils'
|
||||
import { createBadgenHandler, PathArgs } from '../libs/create-badgen-handler'
|
||||
|
||||
export default createBadgenHandler({
|
||||
|
@ -8,18 +8,29 @@ export default createBadgenHandler({
|
|||
'/melpa/v/magit': 'version'
|
||||
},
|
||||
handlers: {
|
||||
'/melpa/:topic<v>/:pkg': handler
|
||||
'/melpa/:topic<v|version>/:pkg': handler
|
||||
}
|
||||
})
|
||||
|
||||
async function handler ({ topic, pkg }: PathArgs) {
|
||||
const badgeUrl = `https://melpa.org/packages/${pkg}-badge.svg`
|
||||
const svg = await got(badgeUrl).text()
|
||||
const title = svg.match(/<title>([^<]+)<\//i)?.[1].trim()
|
||||
const ver = title?.split(':')?.[1]
|
||||
const resp = await got(badgeUrl)
|
||||
const params = isBadge(resp) && parseBadge(resp.body, topic)
|
||||
return params || {
|
||||
subject: 'melpa',
|
||||
status: 'unknown',
|
||||
color: 'grey'
|
||||
}
|
||||
}
|
||||
|
||||
function parseBadge(svg: string, topic: string) {
|
||||
const title = svg.match(/<title>([^<]+)<\//i)?.[1].trim() ?? ''
|
||||
const [_, ver] = title.split(':')
|
||||
if (!ver) return
|
||||
|
||||
switch (topic) {
|
||||
case 'v':
|
||||
case 'version':
|
||||
return {
|
||||
subject: 'melpa',
|
||||
status: version(ver),
|
||||
|
|
28
api/snyk.ts
28
api/snyk.ts
|
@ -1,4 +1,5 @@
|
|||
import got from '../libs/got'
|
||||
import { isBadge } from '../libs/utils'
|
||||
import { createBadgenHandler, PathArgs } from '../libs/create-badgen-handler'
|
||||
|
||||
export default createBadgenHandler({
|
||||
|
@ -18,23 +19,24 @@ async function handler ({ user, repo, branch, targetFile }: PathArgs) {
|
|||
const badgeUrl = `https://snyk.io/test/github/${path}/badge.svg`
|
||||
const searchParams = new URLSearchParams()
|
||||
if (targetFile) searchParams.set('targetFile', targetFile)
|
||||
const svg = await got(badgeUrl, { searchParams, timeout: 3500 }).text()
|
||||
|
||||
const subject = svg.match(/<text x="45"[^>]*?>([^<]+)<\//i)?.[1].trim()
|
||||
const status = svg.match(/<text x="100"[^>]*?>([^<]+)<\//i)?.[1].trim()
|
||||
const color = svg.match(/<path fill="([^"]+)" d="M90/i)?.[1].trim()
|
||||
|
||||
if (!status || !color) {
|
||||
const context = [
|
||||
`${user}/${repo}/${branch}`,
|
||||
targetFile && `targetFile=${targetFile}`
|
||||
].filter(Boolean).join(' ')
|
||||
throw new Error(`Unknown Synk status: ${context}`)
|
||||
const resp = await got(badgeUrl, { searchParams, timeout: 3500 })
|
||||
const params = isBadge(resp) && parseBadge(resp.body)
|
||||
return params || {
|
||||
subject: 'snyk',
|
||||
status: 'unknown',
|
||||
color: 'grey'
|
||||
}
|
||||
}
|
||||
|
||||
function parseBadge(svg: string) {
|
||||
const [subject, status] = [...svg.matchAll(/fill-opacity=[^>]*?>([^<]+)<\//ig)]
|
||||
.map(match => match[1].trim())
|
||||
const color = svg.match(/<path[^>]*?fill="([^"]+)"[^>]*?d="M[^0]/i)?.[1]
|
||||
.trim().replace(/^#/, '')
|
||||
if (!status || !color) return
|
||||
return {
|
||||
subject: subject || 'vulnerabilities',
|
||||
status,
|
||||
color: color.replace(/^#/, '')
|
||||
color
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ import millify from 'millify'
|
|||
|
||||
import coverage from './coverage'
|
||||
import coverageColor from './coverage-color'
|
||||
import isBadge from './is-badge'
|
||||
import scale from './scale'
|
||||
import size from './size'
|
||||
import stars from './stars'
|
||||
|
@ -13,6 +14,7 @@ export {
|
|||
millify,
|
||||
coverage,
|
||||
coverageColor,
|
||||
isBadge,
|
||||
scale,
|
||||
size,
|
||||
stars,
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
export default (resp: import('got').Response) => {
|
||||
const contentType = resp.headers['content-type'] || ''
|
||||
return contentType.includes('image/svg+xml')
|
||||
}
|
Ładowanie…
Reference in New Issue