Files
shields/services/base-svg-scraping.js
Paul Melnikow e983f7bf3b Rewrite vso, rename to [AzureDevops], validate SVG [readthedocs] (#2252)
1. Add validation to BaseSvgScrapingService and update readthedocs accordingly.
2. Rewrite vso and add more tests. Rename it internally to azure-devops. URLs are still `/vso` for now. Should we make a way to let a service register multiple URL patterns?
3. Handle shared code using a functional pattern instead of inheritance. This comes from a discussion https://github.com/badges/shields/pull/2031#issuecomment-417893819. I like the functional approach because it's more direct, nimble, and easy to reason about; plus it allows services to grow from a family of one to two more easily.
2018-11-05 16:52:53 -05:00

58 lines
1.6 KiB
JavaScript

'use strict'
// See available emoji at http://emoji.muan.co/
const emojic = require('emojic')
const BaseService = require('./base')
const trace = require('./trace')
const { InvalidResponse } = require('./errors')
const defaultValueMatcher = />([^<>]+)<\/text><\/g>/
const leadingWhitespace = /(?:\r\n\s*|\r\s*|\n\s*)/g
class BaseSvgScrapingService extends BaseService {
static valueFromSvgBadge(svg, valueMatcher = defaultValueMatcher) {
if (typeof svg !== 'string') {
throw TypeError('Parameter should be a string')
}
const stripped = svg.replace(leadingWhitespace, '')
const match = valueMatcher.exec(stripped)
if (match) {
return match[1]
} else {
throw new InvalidResponse({
prettyMessage: 'unparseable svg response',
underlyingError: Error(`Can't get value from SVG:\n${svg}`),
})
}
}
async _requestSvg({
schema,
valueMatcher,
url,
options = {},
errorMessages = {},
}) {
const logTrace = (...args) => trace.logTrace('fetch', ...args)
const mergedOptions = {
...{ headers: { Accept: 'image/svg+xml' } },
...options,
}
const { buffer } = await this._request({
url,
options: mergedOptions,
errorMessages,
})
logTrace(emojic.dart, 'Response SVG', buffer)
const data = {
message: this.constructor.valueFromSvgBadge(buffer, valueMatcher),
}
logTrace(emojic.dart, 'Response SVG (before validation)', data, {
deep: true,
})
return this.constructor._validate(data, schema)
}
}
module.exports = BaseSvgScrapingService