in generator/autorest.ts [53:157]
export async function generateAutorestConfig(readmePath: string, bicepReadmePath: string) {
// This function takes in an input autorest configuration file (readme.md), and generates a autorest configuration file tailored for use by autorest.bicep (readme.bicep.md)
// We search for markdown yaml blocks containing input .json files, and unconditionally use them to generate output.
// The expected output file should consist of a set of blocks tagged by api version and a 'multi-api' block with links to tags:
//
// ##Bicep
//
// ### Bicep multi-api
// ```yaml $(bicep) && $(multiapi)
// batch:
// - tag: microsoft.securityinsights-2024-03-01
// - tag: microsoft.securityinsights-2024-01-01-preview
// ...
// ```
//
// ### Tag: microsoft.securityinsights-2024-03-01 and bicep
// ```yaml $(tag) == 'microsoft.securityinsights-2024-03-01' && $(bicep)
// input-file:
// - Microsoft.SecurityInsights/stable/2024-03-01/AlertRules.json
// - Microsoft.SecurityInsights/stable/2024-03-01/AutomationRules.json
// ...
// ```
//
// ### Tag: microsoft.securityinsights-2024-01-01-preview and bicep
// ```yaml $(tag) == 'microsoft.securityinsights-2024-01-01-preview' && $(bicep)
// input-file:
// - Microsoft.SecurityInsights/preview/2024-01-01-preview/AlertRules.json
// - Microsoft.SecurityInsights/preview/2024-01-01-preview/AutomationRules.json
// - Microsoft.SecurityInsights/preview/2024-01-01-preview/BillingStatistics.json
// ...
// We expect a path format convention of <provider>/(any/number/of/intervening/folders)/<yyyy>-<mm>-<dd>(|-preview)/<filename>.json
// This information is used to generate individual tags in the generated autorest configuration
// eslint-disable-next-line no-useless-escape
const pathRegex = /^(\$\(this-folder\)\/|)([^\/]+)(?:\/[^\/]+)*\/(\d{4}-\d{2}-\d{2}(|-preview))\/.*\.json$/i;
const readmeContents = await readFile(readmePath, { encoding: 'utf8' });
const readmeMarkdown = markdown.parse(readmeContents);
const inputFiles = new Set<string>();
// we need to look for all autorest configuration elements containing input files, and collect that list of files. These will look like (e.g.):
// ```yaml $(tag) == 'someTag'
// input-file:
// - path/to/file.json
// - path/to/other_file.json
// ```
for (const node of markdown.iterate(readmeMarkdown.markDown)) {
// We're only interested in yaml code blocks
if (node.type !== 'code_block' || !node.info || !node.literal ||
!node.info.trim().startsWith('yaml')) {
continue;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const yamlData = yaml.load(node.literal) as any;
if (yamlData) {
// input-file may be a single string or an array of strings
const inputFile = yamlData['input-file'];
if (typeof inputFile === 'string') {
inputFiles.add(inputFile);
} else if (inputFile instanceof Array) {
for (const i of inputFile) {
inputFiles.add(i);
}
}
}
}
const filesByTag: Record<string, string[]> = {};
for (const file of inputFiles) {
const normalizedFile = normalizeJsonPath(file);
const match = pathRegex.exec(normalizedFile);
if (match) {
// Generate a unique tag. We can't process all of the different API versions in one autorest pass
// because there are constraints on naming uniqueness (e.g. naming of definitions), so we want to pass over
// each API version separately.
const tagName = `${match[2].toLowerCase()}-${match[3].toLowerCase()}`;
if (!filesByTag[tagName]) {
filesByTag[tagName] = [];
}
filesByTag[tagName].push(normalizedFile);
} else {
console.warn(`WARNING: Unable to parse swagger path "${file}"`);
}
}
let generatedContent = `##Bicep
### Bicep multi-api
\`\`\`yaml $(bicep) && $(multiapi)
${yaml.dump({ 'batch': Object.keys(filesByTag).map(tag => ({ 'tag': tag })) }, { lineWidth: 1000 })}
\`\`\`
`;
for (const tag of Object.keys(filesByTag)) {
generatedContent += `### Tag: ${tag} and bicep
\`\`\`yaml $(tag) == '${tag}' && $(bicep)
${yaml.dump({ 'input-file': filesByTag[tag] }, { lineWidth: 1000})}
\`\`\`
`;
}
await writeFile(bicepReadmePath, generatedContent);
}