Skip to content

Commit f6c0622

Browse files
Address PR feedback
1 parent 293d23b commit f6c0622

File tree

2 files changed

+73
-43
lines changed

2 files changed

+73
-43
lines changed

generator/autorest.ts

Lines changed: 67 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,74 @@ const autorestBinary = os.platform() === 'win32' ? 'autorest.cmd' : 'autorest';
1313
const rootDir = `${__dirname}/../`;
1414
const extensionDir = path.resolve(`${rootDir}/bicep-types-az/src/autorest.bicep/`);
1515

16+
function normalizeJsonPath(jsonPath: string) {
17+
// eslint-disable-next-line no-useless-escape
18+
return path.normalize(jsonPath).replace(/[\\\/]/g, '/');
19+
}
20+
21+
async function execAutoRest(tmpFolder: string, params: string[]) {
22+
await executeCmd(__dirname, `${__dirname}/node_modules/.bin/${autorestBinary}`, params);
23+
if (!fileExists(tmpFolder)) {
24+
return [];
25+
}
26+
27+
return await findRecursive(tmpFolder, p => path.extname(p) === '.json');
28+
}
29+
30+
export async function runAutorest(readme: string, tmpFolder: string) {
31+
const autoRestParams = [
32+
`--use=@autorest/modelerfour`,
33+
`--use=${extensionDir}`,
34+
'--bicep',
35+
`--output-folder=${tmpFolder}`,
36+
'--multiapi',
37+
'--title=none',
38+
// This is necessary to avoid failures such as "ERROR: Semantic violation: Discriminator must be a required property." blocking type generation.
39+
// In an ideal world, we'd raise issues in https://github.com/Azure/azure-rest-api-specs and force RP teams to fix them, but this isn't very practical
40+
// as new validations are added continuously, and there's often quite a lag before teams will fix them - we don't want to be blocked by this in generating types.
41+
`--skip-semantics-validation`,
42+
`--arm-schema=true`,
43+
readme,
44+
];
45+
46+
if (constants.autoRestVerboseOutput) {
47+
autoRestParams.push('--verbose');
48+
}
49+
50+
return await execAutoRest(tmpFolder, autoRestParams);
51+
}
52+
1653
export async function generateAutorestConfig(readmePath: string, bicepReadmePath: string) {
54+
// 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)
55+
// We search for markdown yaml blocks containing input .json files, and unconditionally use them to generate output.
56+
// The expected output file should consist of a set of blocks tagged by api version and a 'multi-api' block with links to tags:
57+
//
58+
// ##Bicep
59+
//
60+
// ### Bicep multi-api
61+
// ```yaml $(bicep) && $(multiapi)
62+
// batch:
63+
// - tag: microsoft.securityinsights-2024-03-01
64+
// - tag: microsoft.securityinsights-2024-01-01-preview
65+
// ...
66+
// ```
67+
//
68+
// ### Tag: microsoft.securityinsights-2024-03-01 and bicep
69+
// ```yaml $(tag) == 'microsoft.securityinsights-2024-03-01' && $(bicep)
70+
// input-file:
71+
// - Microsoft.SecurityInsights/stable/2024-03-01/AlertRules.json
72+
// - Microsoft.SecurityInsights/stable/2024-03-01/AutomationRules.json
73+
// ...
74+
// ```
75+
//
76+
// ### Tag: microsoft.securityinsights-2024-01-01-preview and bicep
77+
// ```yaml $(tag) == 'microsoft.securityinsights-2024-01-01-preview' && $(bicep)
78+
// input-file:
79+
// - Microsoft.SecurityInsights/preview/2024-01-01-preview/AlertRules.json
80+
// - Microsoft.SecurityInsights/preview/2024-01-01-preview/AutomationRules.json
81+
// - Microsoft.SecurityInsights/preview/2024-01-01-preview/BillingStatistics.json
82+
// ...
83+
1784
// We expect a path format convention of <provider>/(any/number/of/intervening/folders)/<yyyy>-<mm>-<dd>(|-preview)/<filename>.json
1885
// This information is used to generate individual tags in the generated autorest configuration
1986
// eslint-disable-next-line no-useless-escape
@@ -87,41 +154,4 @@ ${yaml.dump({ 'input-file': filesByTag[tag] }, { lineWidth: 1000})}
87154
}
88155

89156
await writeFile(bicepReadmePath, generatedContent);
90-
}
91-
92-
function normalizeJsonPath(jsonPath: string) {
93-
// eslint-disable-next-line no-useless-escape
94-
return path.normalize(jsonPath).replace(/[\\\/]/g, '/');
95-
}
96-
97-
async function execAutoRest(tmpFolder: string, params: string[]) {
98-
await executeCmd(__dirname, `${__dirname}/node_modules/.bin/${autorestBinary}`, params);
99-
if (!fileExists(tmpFolder)) {
100-
return [];
101-
}
102-
103-
return await findRecursive(tmpFolder, p => path.extname(p) === '.json');
104-
}
105-
106-
export async function runAutorest(readme: string, tmpFolder: string) {
107-
const autoRestParams = [
108-
`--use=@autorest/modelerfour`,
109-
`--use=${extensionDir}`,
110-
'--bicep',
111-
`--output-folder=${tmpFolder}`,
112-
'--multiapi',
113-
'--title=none',
114-
// This is necessary to avoid failures such as "ERROR: Semantic violation: Discriminator must be a required property." blocking type generation.
115-
// In an ideal world, we'd raise issues in https://github.com/Azure/azure-rest-api-specs and force RP teams to fix them, but this isn't very practical
116-
// as new validations are added continuously, and there's often quite a lag before teams will fix them - we don't want to be blocked by this in generating types.
117-
`--skip-semantics-validation`,
118-
`--arm-schema=true`,
119-
readme,
120-
];
121-
122-
if (constants.autoRestVerboseOutput) {
123-
autoRestParams.push('--verbose');
124-
}
125-
126-
return await execAutoRest(tmpFolder, autoRestParams);
127157
}

generator/processors/helpers.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
// eslint-disable-next-line @typescript-eslint/no-explicit-any
55
export function replaceRefByName(schema: any, definitionName: string, replacement: any) {
6-
doRecursively(schema, val => {
6+
transformSchemaRecursively(schema, val => {
77
if (val['$ref'] === `#/definitions/${definitionName}`) {
88
return replacement;
99
}
@@ -19,7 +19,7 @@ export function replaceCyclicRefByName(schema: any, definitionName: string, repl
1919
for (const refName in schema.definitions) {
2020
refVertices[refName] = new Set<string>();
2121

22-
doRecursively(schema.definitions[refName], val => {
22+
transformSchemaRecursively(schema.definitions[refName], val => {
2323
if (val['$ref'] && val['$ref'].startsWith('#/definitions/')) {
2424
refVertices[refName].add(val['$ref'].substring('#/definitions/'.length));
2525
}
@@ -35,19 +35,19 @@ export function replaceCyclicRefByName(schema: any, definitionName: string, repl
3535
}
3636

3737
// eslint-disable-next-line @typescript-eslint/no-explicit-any
38-
function doRecursively(schema: any, func: (input: any) => any) {
38+
function transformSchemaRecursively(schema: any, transformFunc: (input: any) => any) {
3939
if (typeof schema === 'object') {
4040
for (const key of Object.keys(schema)) {
41-
schema[key] = doRecursively(schema[key], func);
41+
schema[key] = transformSchemaRecursively(schema[key], transformFunc);
4242
}
4343
}
4444
else if (Array.isArray(schema)) {
4545
for (let i = 0; i < schema.length; i++) {
46-
schema[i] = doRecursively(schema[i], func);
46+
schema[i] = transformSchemaRecursively(schema[i], transformFunc);
4747
}
4848
}
4949

50-
return func(schema);
50+
return transformFunc(schema);
5151
}
5252

5353
function findCyclicReferencingDefinitions(refVertices: Record<string, Set<string>>, definitionName: string) {

0 commit comments

Comments
 (0)