@azure/avocado
Advanced tools
Comparing version 0.7.1 to 0.7.2
# Changelog | ||
## 0.7.2 | ||
- Add rule MULTIPLE_API_VERSION to validate if the default tag in readme.md contains multiple API version. | ||
## 0.7.1 | ||
@@ -4,0 +8,0 @@ |
@@ -31,2 +31,5 @@ "use strict"; | ||
} | ||
if (error.code === 'MULTIPLE_API_VERSION') { | ||
return fileChanges.some(item => exports.hasCommonRPFolder(item.path, error.readMeUrl)); | ||
} | ||
return false; | ||
@@ -33,0 +36,0 @@ }; |
import { JsonParseError } from './errors'; | ||
import * as jsonParser from '@ts-common/json-parser'; | ||
import * as format from '@azure/swagger-validation-common'; | ||
declare type ErrorMessage = 'The example JSON file is not referenced from the swagger file.' | 'The swagger JSON file is not referenced from the readme file.' | 'The `readme.md` is not an AutoRest markdown file.' | 'The JSON file is not found but it is referenced from the readme file.' | 'The JSON file has a circular reference.' | 'The file is not a valid JSON file.' | 'Can not find readme.md in the folder. If no readme.md file, it will block SDK generation.' | 'The API version of the swagger is inconsistent with its file path.'; | ||
declare type ErrorMessage = 'The example JSON file is not referenced from the swagger file.' | 'The swagger JSON file is not referenced from the readme file.' | 'The `readme.md` is not an AutoRest markdown file.' | 'The JSON file is not found but it is referenced from the readme file.' | 'The JSON file has a circular reference.' | 'The file is not a valid JSON file.' | 'Can not find readme.md in the folder. If no readme.md file, it will block SDK generation.' | 'The API version of the swagger is inconsistent with its file path.' | 'The default tag contains multiple API versions swaggers.'; | ||
export interface IErrorBase { | ||
@@ -19,2 +19,8 @@ readonly level: 'Warning' | 'Error' | 'Info'; | ||
} & IErrorBase; | ||
export declare type MultipleApiVersion = { | ||
readonly code: 'MULTIPLE_API_VERSION'; | ||
readonly message: ErrorMessage; | ||
readonly readMeUrl: string; | ||
readonly tag: string | undefined; | ||
} & IErrorBase; | ||
export declare type FileError = { | ||
@@ -32,4 +38,4 @@ readonly code: 'NO_JSON_FILE_FOUND' | 'UNREFERENCED_JSON_FILE' | 'CIRCULAR_REFERENCE' | 'INCONSISTENT_API_VERSION'; | ||
export declare const getPathInfoFromError: (error: Error) => format.JsonPath[]; | ||
export declare type Error = JsonParseError | FileError | NotAutoRestMarkDown | MissingReadmeError; | ||
export declare type Error = JsonParseError | FileError | NotAutoRestMarkDown | MissingReadmeError | MultipleApiVersion; | ||
export {}; | ||
//# sourceMappingURL=errors.d.ts.map |
@@ -22,2 +22,10 @@ "use strict"; | ||
]; | ||
case 'MULTIPLE_API_VERSION': | ||
return [ | ||
{ tag: 'readme', path: format.blobHref(format.getRelativeSwaggerPathToRepo(error.readMeUrl)) }, | ||
{ | ||
tag: 'tag', | ||
path: format.blobHref(format.getRelativeSwaggerPathToRepo(`${error.readMeUrl}#tag-${error.tag}`)), | ||
}, | ||
]; | ||
case 'MISSING_README': | ||
@@ -24,0 +32,0 @@ return [{ tag: 'folder', path: format.blobHref(format.getRelativeSwaggerPathToRepo(error.folderUrl)) }]; |
@@ -0,2 +1,4 @@ | ||
import * as md from '@ts-common/commonmark-to-markdown'; | ||
import * as asyncIt from '@ts-common/async-iterator'; | ||
import * as commonmark from 'commonmark'; | ||
import * as cli from './cli'; | ||
@@ -9,2 +11,11 @@ import * as git from './git'; | ||
/** | ||
* @return return undefined indicates not found, otherwise return non-empty string. | ||
*/ | ||
export declare const getDefaultTag: (markDown: commonmark.Node) => string | undefined; | ||
/** | ||
* @return return undefined indicates not found, otherwise return non-empty string. | ||
*/ | ||
export declare const getVersionFromInputFile: (filePath: string) => string | undefined; | ||
export declare const isContainsMultiVersion: (m: md.MarkDownEx) => boolean; | ||
/** | ||
* The function validates files in the given `cwd` folder and returns errors. | ||
@@ -11,0 +22,0 @@ */ |
@@ -25,2 +25,3 @@ "use strict"; | ||
const err = tslib_1.__importStar(require("./errors")); | ||
const YAML = tslib_1.__importStar(require("js-yaml")); | ||
// tslint:disable-next-line: no-require-imports | ||
@@ -62,2 +63,8 @@ const nodeObjectHash = require("node-object-hash"); | ||
} | ||
case 'MULTIPLE_API_VERSION': { | ||
return { | ||
code: error.code, | ||
url: error.readMeUrl, | ||
}; | ||
} | ||
} | ||
@@ -89,2 +96,71 @@ }; | ||
}); | ||
const safeLoad = (content) => { | ||
try { | ||
return YAML.safeLoad(content); | ||
} | ||
catch (err) { | ||
return undefined; | ||
} | ||
}; | ||
/** | ||
* @return return undefined indicates not found, otherwise return non-empty string. | ||
*/ | ||
exports.getDefaultTag = (markDown) => { | ||
const startNode = markDown; | ||
const codeBlockMap = openApiMd.getCodeBlocksAndHeadings(startNode); | ||
const latestHeader = 'Basic Information'; | ||
const headerBlock = codeBlockMap[latestHeader]; | ||
if (headerBlock && headerBlock.literal) { | ||
const latestDefinition = safeLoad(headerBlock.literal); | ||
if (latestDefinition && latestDefinition.tag) { | ||
return latestDefinition.tag; | ||
} | ||
} | ||
for (const idx of Object.keys(codeBlockMap)) { | ||
const block = codeBlockMap[idx]; | ||
if (!block || !block.info || !block.literal || !/^(yaml|json)$/.test(block.info.trim().toLowerCase())) { | ||
continue; | ||
} | ||
const latestDefinition = safeLoad(block.literal); | ||
if (latestDefinition && latestDefinition.tag) { | ||
return latestDefinition.tag; | ||
} | ||
} | ||
return undefined; | ||
}; | ||
/** | ||
* @return return undefined indicates not found, otherwise return non-empty string. | ||
*/ | ||
exports.getVersionFromInputFile = (filePath) => { | ||
const apiVersionRegex = /^\d{4}-\d{2}-\d{2}(|-preview)$/; | ||
const segments = filePath.split('/').slice(0, -1); | ||
if (segments && segments.length > 1) { | ||
for (const s of segments) { | ||
if (apiVersionRegex.test(s)) { | ||
return s; | ||
} | ||
} | ||
} | ||
return undefined; | ||
}; | ||
exports.isContainsMultiVersion = (m) => { | ||
const defaultTag = exports.getDefaultTag(m.markDown); | ||
if (!defaultTag) { | ||
return false; | ||
} | ||
const inputFiles = openApiMd.getInputFilesForTag(m.markDown, defaultTag); | ||
if (inputFiles) { | ||
const versions = new Set(); | ||
for (const file of inputFiles) { | ||
const version = exports.getVersionFromInputFile(file); | ||
if (version) { | ||
versions.add(version); | ||
if (versions.size > 1) { | ||
return true; | ||
} | ||
} | ||
} | ||
} | ||
return false; | ||
}; | ||
const jsonParse = (fileName, file) => { | ||
@@ -263,2 +339,11 @@ // tslint:disable-next-line:readonly-array | ||
} | ||
if (exports.isContainsMultiVersion(m)) { | ||
yield { | ||
code: 'MULTIPLE_API_VERSION', | ||
message: 'The default tag contains multiple API versions swaggers.', | ||
readMeUrl: readMePath, | ||
tag: exports.getDefaultTag(m.markDown), | ||
level: 'Warning', | ||
}; | ||
} | ||
}); | ||
@@ -265,0 +350,0 @@ /** |
{ | ||
"name": "@azure/avocado", | ||
"version": "0.7.1", | ||
"version": "0.7.2", | ||
"description": "A validator of OpenAPI configurations", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
@@ -113,2 +113,10 @@ # Avocado | ||
### MULTIPLE_API_VERSION | ||
Level: WARNING | ||
The default tag should contain only one API version swagger. | ||
To solve this warning , you should copy the swaggers of old version into the current version folder. | ||
## Contributing | ||
@@ -115,0 +123,0 @@ |
@@ -84,2 +84,5 @@ // Copyright (c) Microsoft Corporation. All rights reserved. | ||
} | ||
if (error.code === 'MULTIPLE_API_VERSION') { | ||
return fileChanges.some(item => hasCommonRPFolder(item.path, error.readMeUrl)) | ||
} | ||
return false | ||
@@ -86,0 +89,0 @@ } |
@@ -17,2 +17,3 @@ import { JsonParseError } from './errors' | ||
| 'The API version of the swagger is inconsistent with its file path.' | ||
| 'The default tag contains multiple API versions swaggers.' | ||
@@ -36,2 +37,9 @@ export interface IErrorBase { | ||
export type MultipleApiVersion = { | ||
readonly code: 'MULTIPLE_API_VERSION' | ||
readonly message: ErrorMessage | ||
readonly readMeUrl: string | ||
readonly tag: string | undefined | ||
} & IErrorBase | ||
export type FileError = { | ||
@@ -67,2 +75,10 @@ readonly code: 'NO_JSON_FILE_FOUND' | 'UNREFERENCED_JSON_FILE' | 'CIRCULAR_REFERENCE' | 'INCONSISTENT_API_VERSION' | ||
] | ||
case 'MULTIPLE_API_VERSION': | ||
return [ | ||
{ tag: 'readme', path: format.blobHref(format.getRelativeSwaggerPathToRepo(error.readMeUrl)) }, | ||
{ | ||
tag: 'tag', | ||
path: format.blobHref(format.getRelativeSwaggerPathToRepo(`${error.readMeUrl}#tag-${error.tag}`)), | ||
}, | ||
] | ||
case 'MISSING_README': | ||
@@ -75,2 +91,2 @@ return [{ tag: 'folder', path: format.blobHref(format.getRelativeSwaggerPathToRepo(error.folderUrl)) }] | ||
export type Error = JsonParseError | FileError | NotAutoRestMarkDown | MissingReadmeError | ||
export type Error = JsonParseError | FileError | NotAutoRestMarkDown | MissingReadmeError | MultipleApiVersion |
@@ -21,2 +21,3 @@ // Copyright (c) Microsoft Corporation. All rights reserved. | ||
import * as format from '@azure/swagger-validation-common' | ||
import * as YAML from 'js-yaml' | ||
@@ -62,2 +63,8 @@ // tslint:disable-next-line: no-require-imports | ||
} | ||
case 'MULTIPLE_API_VERSION': { | ||
return { | ||
code: error.code, | ||
url: error.readMeUrl, | ||
} | ||
} | ||
} | ||
@@ -95,2 +102,75 @@ } | ||
const safeLoad = (content: string) => { | ||
try { | ||
return YAML.safeLoad(content) | ||
} catch (err) { | ||
return undefined | ||
} | ||
} | ||
/** | ||
* @return return undefined indicates not found, otherwise return non-empty string. | ||
*/ | ||
export const getDefaultTag = (markDown: commonmark.Node): string | undefined => { | ||
const startNode = markDown | ||
const codeBlockMap = openApiMd.getCodeBlocksAndHeadings(startNode) | ||
const latestHeader = 'Basic Information' | ||
const headerBlock = codeBlockMap[latestHeader] | ||
if (headerBlock && headerBlock.literal) { | ||
const latestDefinition = safeLoad(headerBlock.literal) | ||
if (latestDefinition && latestDefinition.tag) { | ||
return latestDefinition.tag | ||
} | ||
} | ||
for (const idx of Object.keys(codeBlockMap)) { | ||
const block = codeBlockMap[idx] | ||
if (!block || !block.info || !block.literal || !/^(yaml|json)$/.test(block.info.trim().toLowerCase())) { | ||
continue | ||
} | ||
const latestDefinition = safeLoad(block.literal) | ||
if (latestDefinition && latestDefinition.tag) { | ||
return latestDefinition.tag | ||
} | ||
} | ||
return undefined | ||
} | ||
/** | ||
* @return return undefined indicates not found, otherwise return non-empty string. | ||
*/ | ||
export const getVersionFromInputFile = (filePath: string): string | undefined => { | ||
const apiVersionRegex = /^\d{4}-\d{2}-\d{2}(|-preview)$/ | ||
const segments = filePath.split('/').slice(0, -1) | ||
if (segments && segments.length > 1) { | ||
for (const s of segments) { | ||
if (apiVersionRegex.test(s)) { | ||
return s | ||
} | ||
} | ||
} | ||
return undefined | ||
} | ||
export const isContainsMultiVersion = (m: md.MarkDownEx): boolean => { | ||
const defaultTag = getDefaultTag(m.markDown) | ||
if (!defaultTag) { | ||
return false | ||
} | ||
const inputFiles = openApiMd.getInputFilesForTag(m.markDown, defaultTag) | ||
if (inputFiles) { | ||
const versions = new Set<string>() | ||
for (const file of inputFiles) { | ||
const version = getVersionFromInputFile(file) | ||
if (version) { | ||
versions.add(version) | ||
if (versions.size > 1) { | ||
return true | ||
} | ||
} | ||
} | ||
} | ||
return false | ||
} | ||
const jsonParse = (fileName: string, file: string) => { | ||
@@ -328,2 +408,11 @@ // tslint:disable-next-line:readonly-array | ||
} | ||
if (isContainsMultiVersion(m)) { | ||
yield { | ||
code: 'MULTIPLE_API_VERSION', | ||
message: 'The default tag contains multiple API versions swaggers.', | ||
readMeUrl: readMePath, | ||
tag: getDefaultTag(m.markDown), | ||
level: 'Warning', | ||
} | ||
} | ||
}) | ||
@@ -330,0 +419,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
108005
1833
134