Files
shields/services/transform-example.js
Paul Melnikow 2ece7c4ee2 Wrap HTML in __html in service def export (#2791)
The intention of wrapping HTML in an `__html` is to avoid accidentally unsafe rendering of something that is non-html.

Including this in the definition export solves the problem, and does not seem too onerous for other possible users of that file.

Close #2725
2019-01-17 13:47:23 -05:00

167 lines
4.0 KiB
JavaScript

'use strict'
const Joi = require('joi')
const pathToRegexp = require('path-to-regexp')
const optionalObjectOfKeyValues = Joi.object().pattern(
/./,
Joi.string().allow(null)
)
const optionalServiceData = Joi.object({
label: Joi.string(),
message: Joi.alternatives()
.try(
Joi.string()
.allow('')
.required(),
Joi.number()
)
.required(),
color: Joi.string(),
})
const schema = Joi.object({
// This should be:
// title: Joi.string().required(),
title: Joi.string(),
namedParams: optionalObjectOfKeyValues,
queryParams: optionalObjectOfKeyValues.default({}),
pattern: Joi.string(),
staticPreview: optionalServiceData,
previewUrl: Joi.string(),
keywords: Joi.array()
.items(Joi.string())
.default([]),
documentation: Joi.string(), // Valid HTML.
}).required()
function validateExample(example, index, ServiceClass) {
const result = Joi.attempt(
example,
schema,
`Example for ${ServiceClass.name} at index ${index}`
)
const { namedParams, pattern, staticPreview, previewUrl } = result
if (staticPreview) {
if (!pattern && !ServiceClass.route.pattern) {
throw new Error(
`Static preview for ${
ServiceClass.name
} at index ${index} does not declare a pattern`
)
} else if (!namedParams) {
throw new Error(
`Static preview for ${
ServiceClass.name
} at index ${index} does not declare namedParams`
)
}
if (previewUrl) {
throw new Error(
`Static preview for ${
ServiceClass.name
} at index ${index} also declares a dynamic previewUrl, which is not allowed`
)
}
if (pattern === ServiceClass.route.pattern) {
throw new Error(
`Example for ${
ServiceClass.name
} at index ${index} declares a redundant pattern which should be removed`
)
}
// Make sure we can build the full URL using these patterns.
try {
pathToRegexp.compile(pattern || ServiceClass.route.pattern)(namedParams)
} catch (e) {
throw Error(
`In example for ${
ServiceClass.name
} at index ${index}, ${e.message.toLowerCase()}`
)
}
// Make sure there are no extra keys.
let keys = []
pathToRegexp(pattern || ServiceClass.route.pattern, keys)
keys = keys.map(({ name }) => name)
const extraKeys = Object.keys(namedParams).filter(k => !keys.includes(k))
if (extraKeys.length) {
throw Error(
`In example for ${
ServiceClass.name
} at index ${index}, namedParams contains unknown keys: ${extraKeys.join(
', '
)}`
)
}
} else if (!previewUrl) {
throw Error(
`Example for ${
ServiceClass.name
} at index ${index} is missing required previewUrl or staticPreview`
)
}
return result
}
function transformExample(inExample, index, ServiceClass) {
const {
// We should get rid of this transform, since the class name is never what
// we want to see.
title = ServiceClass.name,
namedParams,
queryParams,
pattern,
staticPreview,
previewUrl,
keywords,
documentation,
} = validateExample(inExample, index, ServiceClass)
let example
if (namedParams) {
example = {
pattern: ServiceClass._makeFullUrl(pattern || ServiceClass.route.pattern),
namedParams,
queryParams,
}
} else {
example = {
path: ServiceClass._makeFullUrl(previewUrl),
queryParams,
}
}
let preview
if (staticPreview) {
const {
text: [label, message],
color,
} = ServiceClass._makeBadgeData({}, staticPreview)
preview = { label, message: `${message}`, color }
} else {
preview = {
path: ServiceClass._makeFullUrl(previewUrl),
queryParams,
}
}
return {
title,
example,
preview,
keywords,
documentation: documentation ? { __html: documentation } : undefined,
}
}
module.exports = {
validateExample,
transformExample,
}