Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
const recording = JSON.parse(fs.readFileSync(recordingFileName).toString())
const paths = api.paths
let pathIndex = 0
let pathParams: MutableStringMap = {}
for (const path of keys(paths)) {
pathIndex++
const searchResult = path.match(/\/{\w*\}/g)
const pathParts = path.split("/")
let pathToMatch = path
pathParams = {}
if (searchResult !== null) {
for (const match of searchResult) {
const splitRegEx = /[{}]/
const pathParam = match.split(splitRegEx)[1]
for (const [part, value] of _.entries(pathParts)) {
const pathPart = "/" + value
if (pathPart.localeCompare(match) === 0) {
pathParams[pathParam] = part
}
}
pathToMatch = pathToMatch.replace(match, "/[^/]+")
}
}
let newPathToMatch = pathToMatch.replace(/\//g, "\\/")
newPathToMatch = newPathToMatch + "$"
// for this API path (and method), try to find it in the recording file, and get
// the data
const recordingEntries: StringMap = recording.Entries
let entryIndex = 0
const queryParams: MutableStringMap = {}
for (const [responseStatusCode, value] of sm.entries(responseValidation)) {
this.constructResponseResultWrapper(
operationId,
responseStatusCode,
value.errors,
value.warnings,
exampleType,
scenario
)
}
}
}
} else if (exampleType === C.exampleInSpec) {
if (
result.requestValidation &&
toArray(sm.keys(result.requestValidation as sm.StringMap)).length
) {
// requestValidation
const validationResult = result.requestValidation.validationResult
if (validationResult === undefined) {
throw new Error("validationResult is undefined")
}
const requestValidationErrors = validationResult.errors
const requestValidationWarnings = validationResult.warnings
this.constructRequestResultWrapper(
operationId,
requestValidationErrors,
requestValidationWarnings,
exampleType
)
}
if (result.responseValidation && !sm.isEmpty(result.responseValidation)) {
private unifyXmsPaths(): void {
// unify x-ms-paths into paths
const xmsPaths = this.specInJson["x-ms-paths"]
const paths = this.specInJson.paths as PathsObject
if (xmsPaths && xmsPaths instanceof Object && toArray(sm.keys(xmsPaths)).length > 0) {
for (const [property, v] of sm.entries(xmsPaths)) {
paths[property] = v
}
this.specInJson.paths = utils.mergeObjects(xmsPaths, paths)
}
}
const rootNode = new PolymorphicTree(name)
const definitions = this.specInJson.definitions as DefinitionsObject
// Adding the model name or it's discriminator value as an enum constraint with one value
// (constant) on property marked as discriminator
const definition = definitions[name]
if (definition && definition.properties) {
// all derived types should have `"type": "object"`.
// otherwise it may pass validation for other types, such as `string`.
// see also https://github.com/Azure/oav/issues/390
definition.type = "object"
const d = definition.properties[discriminator]
if (d) {
const required = definition.required
if (!isArray(required)) {
definition.required = [discriminator]
} else if (required.find(v => v === discriminator) === undefined) {
definition.required = [...required, discriminator]
}
const val = definition["x-ms-discriminator-value"] || name
// Ensure that the property marked as a discriminator has only one value in the enum
// constraint for that model and it
// should be the one that is the model name or the value indicated by
// x-ms-discriminator-value. This will make the discriminator
// property a constant (in json schema terms).
if (d.$ref) {
delete d.$ref
}
const xMsEnum = d["x-ms-enum"]
if (xMsEnum !== undefined) {
// if modelAsString is set to `true` then validator will always succeeded on any string.
const applySuppression = (result: SwaggerObject) => {
const rootInfo = getFilePosition(result)
// apply suppression
for (const s of suppressionArray) {
if (s.where !== undefined) {
const paths = it.flatMap(it.isArray(s.where) ? s.where : [s.where], where => {
try {
return jp.paths(result, where)
} catch (e) {
log.error(e)
// TODO: return the error.
return []
}
})
for (const p of paths) {
// drop "$" and apply suppressions.
setSuppression(getDescendantFilePosition(result, it.drop(p)), s)
}
} else {
setSuppression(rootInfo, s)
}
}
export const getSuppressions = async (specPath: string): Promise => {
// find readme.md
try {
const readMe = await amd.findReadMe(path.dirname(specPath))
if (readMe === undefined) {
return undefined
}
const readMeStr = await vfs.readFile(readMe)
const cmd = md.parse(readMeStr)
const suppressionCodeBlock = amd.getCodeBlocksAndHeadings(cmd.markDown).Suppression
if (suppressionCodeBlock === undefined) {
return undefined
}
const suppression = amd.getYamlFromNode(suppressionCodeBlock) as amd.Suppression
if (!it.isArray(suppression.directive)) {
return undefined
}
return suppression
} catch (err) {
log.warn(`Unable to load and parse suppression file. Error: ${err}`)
return undefined
}
}
if (node.path) {
// in this case the path will be set to the url instead of the path to the property
if (node.code === "INVALID_REQUEST_PARAMETER" && node.in === "body") {
node.path = []
} else if (
(node.in === "query" || node.in === "path") &&
node.path[0] === "paths" &&
node.name
) {
// in this case we will want to normalize the path with the uri and the paramter name
node.path = [node.path[1], node.name]
}
path = consolidatePath(path, node.path)
}
const serializedErrors = flatMap(node.errors, validationError =>
serializeErrors(validationError, path)
).toArray()
const serializedInner = fold(
node.inner,
(acc, validationError) => {
const errs = serializeErrors(validationError, path)
errs.forEach(err => {
const similarErr = acc.find(el => areErrorsSimilar(err, el))
if (similarErr && similarErr.path) {
if (!similarErr.similarPaths) {
similarErr.similarPaths = []
}
similarErr.similarPaths.push(err.path as string)
if (!similarErr.similarJsonPaths) {
}
// ensure content-type header is present
if (!(exampleResponseHeaders["content-type"] || exampleResponseHeaders["Content-Type"])) {
exampleResponseHeaders["content-type"] = utils.getJsonContentType(operation.produces)
}
const exampleResponse = new ResponseWrapper(
exampleResponseStatusCode,
exampleResponseBody,
exampleResponseHeaders
)
const validationResult = this.validateResponse(operation, exampleResponse)
result[exampleResponseStatusCode] = validationResult
}
const responseWithoutXmsExamples = toArray(
filter(sm.keys(responsesInSwagger), statusCode => statusCode !== "default")
)
if (responseWithoutXmsExamples && responseWithoutXmsExamples.length) {
const msg =
`Following response status codes "${responseWithoutXmsExamples.toString()}" for ` +
`operation "${operation.operationId}" were present in the swagger spec, ` +
`however they were not present in x-ms-examples. Please provide them.`
const e = this.constructErrorObject({
code: C.ErrorCodes.ResponseStatusCodeNotInExample,
message: msg,
source: operation.definition
})
setPositionAndUrl(e, getTitle(operation.definition))
log.error(e as any)
responseWithoutXmsExamples.forEach(statusCode => (result[statusCode] = { errors: [e] }))
}
} else if (
(node.in === "query" || node.in === "path") &&
node.path[0] === "paths" &&
node.name
) {
// in this case we will want to normalize the path with the uri and the paramter name
node.path = [node.path[1], node.name]
}
path = consolidatePath(path, node.path)
}
const serializedErrors = flatMap(node.errors, validationError =>
serializeErrors(validationError, path)
).toArray()
const serializedInner = fold(
node.inner,
(acc, validationError) => {
const errs = serializeErrors(validationError, path)
errs.forEach(err => {
const similarErr = acc.find(el => areErrorsSimilar(err, el))
if (similarErr && similarErr.path) {
if (!similarErr.similarPaths) {
similarErr.similarPaths = []
}
similarErr.similarPaths.push(err.path as string)
if (!similarErr.similarJsonPaths) {
similarErr.similarJsonPaths = []
}
similarErr.similarJsonPaths.push(err.jsonPath as string)
} else {
const rootInfo = getFilePosition(result)
// apply suppression
for (const s of suppressionArray) {
if (s.where !== undefined) {
const paths = it.flatMap(it.isArray(s.where) ? s.where : [s.where], where => {
try {
return jp.paths(result, where)
} catch (e) {
log.error(e)
// TODO: return the error.
return []
}
})
for (const p of paths) {
// drop "$" and apply suppressions.
setSuppression(getDescendantFilePosition(result, it.drop(p)), s)
}
} else {
setSuppression(rootInfo, s)
}
}
return result
}