in src/index.ts [694:815]
tag: getDefaultTag(m.markDown),
path: readMePath,
level: 'Warning',
}
}
})
/**
* Validate spec files in two steps:
* 1. `DFSTraversalValidate`: Analyze specs as a directed graph to detect circular reference and
* generate `blackSet` that contains all explored specs.
* 2. Get difference set between `allInputFileSet` and `blackSet`, and then report `UNREFERENCED_JSON_FILE` error.
*
* @param inputFileSet files referenced from 'readme.md' is the subset of `allInputFileSet`
* @param allInputFileSet files appear in specification folder.
*/
const validateInputFiles = (
inputFileSet: Set<Specification>,
allInputFileSet: Set<Specification>,
): asyncIt.AsyncIterableEx<err.Error> =>
// tslint:disable-next-line: no-async-without-await
asyncIt.iterable<err.Error>(async function*() {
// report errors if the `dir` folder has JSON files where exist circular reference
const graySet = new Set<string>()
const blackSet = new Set<string>()
for (const current of inputFileSet) {
yield* DFSTraversalValidate(current, graySet, blackSet)
}
// report errors if the `dir` folder has JSON files which are not referenced
yield* asyncIt
.fromSync(allInputFileSet.values())
.filter(spec => !blackSet.has(spec.path))
.map<err.Error>(spec => ({
code: 'UNREFERENCED_JSON_FILE',
message:
spec.kind === 'SWAGGER'
? 'The swagger JSON file is not referenced from the readme file.'
: 'The example JSON file is not referenced from the swagger file.',
level: 'Error',
readMeUrl: spec.readMePath,
jsonUrl: spec.path,
path: spec.path,
}))
})
const getInputFilesFromReadme = (readMePath: string): asyncIt.AsyncIterableEx<Specification> =>
asyncIt.iterable<Specification>(async function*() {
const file = await tscommonFs.readFile(readMePath)
const m = md.parse(file.toString())
const dir = path.dirname(readMePath)
yield* openApiMd
.getInputFiles(m.markDown)
.map(f => f.replace('$(this-folder)', '.'))
.uniq()
.map(f => path.resolve(path.join(dir, ...f.split('\\'))))
.map<Specification>(f => ({ path: f, readMePath, kind: isExample(f) ? 'EXAMPLE' : 'SWAGGER' }))
})
const getAllInputFilesUnderReadme = (readMePath: string): asyncIt.AsyncIterableEx<Specification> =>
// tslint:disable-next-line: no-async-without-await
asyncIt.iterable<Specification>(async function*() {
const dir = path.dirname(readMePath)
yield* tscommonFs
.recursiveReaddir(dir)
.filter(filePath => path.extname(filePath) === '.json')
.map<Specification>(filePath => ({
path: filePath,
readMePath,
kind: isExample(filePath) ? 'EXAMPLE' : 'SWAGGER',
}))
})
const validateIllegalFiles = (dir: string): asyncIt.AsyncIterableEx<err.Error> =>
tscommonFs
.recursiveReaddir(dir)
.filter(f => (f.includes('resource-manager') || f.includes('data-plane')) && path.extname(f) === '.cadl')
.map<err.Error>(f => ({
code: 'INVALID_TYPESPEC_LOCATION',
message: 'TypeSpec file is not allowed in resource-manager or data-plane folder.',
level: 'Error',
path: f,
}))
/**
* Validate global specification folder and prepare arguments for `validateInputFiles`.
*/
const validateFolder = (dir: string) =>
asyncIt.iterable<err.Error>(async function*() {
yield* validateIllegalFiles(dir)
const allReadMeFiles = tscommonFs.recursiveReaddir(dir).filter(f => path.basename(f).toLowerCase() === 'readme.md')
yield* validateRPFolderMustContainReadme(dir)
yield* allReadMeFiles.flatMap(validateReadMeFile)
const referencedFiles = await allReadMeFiles
.flatMap(getInputFilesFromReadme)
.fold((fileSet: Set<Specification>, spec) => {
fileSet.add(spec)
return fileSet
}, new Set<Specification>())
const allFiles = await allReadMeFiles
.flatMap(getAllInputFilesUnderReadme)
.fold((fileSet: Set<Specification>, spec) => {
fileSet.add(spec)
return fileSet
}, new Set<Specification>())
yield* validateInputFiles(referencedFiles, allFiles)
yield* validateRPMustContainAllLatestApiVersionSwagger(dir)
})
/**
* Creates a map of unique errors for the given folder `cwd`.
*/
const avocadoForDir = async (dir: string, exclude: string[], include: string[]) => {
const map = new Map<string, err.Error>()
if (fs.existsSync(dir)) {
console.log(`avocadoForDir: ${dir}`)
for await (const e of validateFolder(dir)) {