|
| 1 | +import { readFile } from "fs/promises"; |
| 2 | +import { join } from "path"; |
| 3 | +import { parse as yamlParse } from "yaml"; |
| 4 | +import { Rule } from "../rule.js"; |
| 5 | +import { RuleResult } from "../rule-result.js"; |
| 6 | +import { checkFileExists } from "../utils.js"; |
| 7 | + |
| 8 | +export class LinterRulesetRule implements Rule { |
| 9 | + readonly name = "LinterRuleset"; |
| 10 | + |
| 11 | + readonly description = |
| 12 | + "Ensures each spec includes the correct linter ruleset (data-plane or management-plane)"; |
| 13 | + |
| 14 | + async execute(folder: string): Promise<RuleResult> { |
| 15 | + let success = true; |
| 16 | + let stdOutput = ""; |
| 17 | + let errorOutput = ""; |
| 18 | + |
| 19 | + const configFile = join(folder, "tspconfig.yaml"); |
| 20 | + const configText = await readFile(configFile, "utf8"); |
| 21 | + const config = yamlParse(configText); |
| 22 | + |
| 23 | + const rpFolder = |
| 24 | + config.options?.["@azure-tools/typespec-autorest"]?.["azure-resource-provider-folder"]; |
| 25 | + stdOutput += `azure-resource-provider-folder: ${JSON.stringify(rpFolder)}\n`; |
| 26 | + |
| 27 | + const mainTspExists = await checkFileExists(join(folder, "main.tsp")); |
| 28 | + const clientTspExists = await checkFileExists(join(folder, "client.tsp")); |
| 29 | + let files = []; |
| 30 | + if (mainTspExists) { |
| 31 | + files.push("main.tsp"); |
| 32 | + } |
| 33 | + if (clientTspExists) { |
| 34 | + files.push("client.tsp"); |
| 35 | + } |
| 36 | + stdOutput += `files: ${JSON.stringify(files)}\n`; |
| 37 | + |
| 38 | + const linterExtends = config.linter?.extends; |
| 39 | + stdOutput += `linter.extends: ${JSON.stringify(linterExtends)}`; |
| 40 | + |
| 41 | + let requiredRuleset = ""; |
| 42 | + if (rpFolder?.trim()?.endsWith("resource-manager")) { |
| 43 | + requiredRuleset = "@azure-tools/typespec-azure-resource-manager/all"; |
| 44 | + } else if (rpFolder?.trim()?.endsWith("data-plane")) { |
| 45 | + requiredRuleset = "@azure-tools/typespec-azure-core/all"; |
| 46 | + } else if (clientTspExists && !mainTspExists) { |
| 47 | + // Assume folders with no autorest setting, containing only "client.tsp" but no "main.tsp", |
| 48 | + // are data-plane (e.g. HealthInsights.TrialMatcher) |
| 49 | + requiredRuleset = "@azure-tools/typespec-azure-core/all"; |
| 50 | + } else { |
| 51 | + // Cannot determine if spec is data-plane or resource-manager, so cannot know |
| 52 | + // which linter ruleset is required. |
| 53 | + success = false; |
| 54 | + errorOutput += |
| 55 | + "tspconfig.yaml must define the following property:\n" + |
| 56 | + "\n" + |
| 57 | + "options:\n" + |
| 58 | + ' "@azure-tools/typespec-autorest":\n' + |
| 59 | + ' azure-resource-provider-folder: "data-plane" | "resource-manager"\n'; |
| 60 | + } |
| 61 | + |
| 62 | + if (requiredRuleset && !linterExtends?.includes(requiredRuleset)) { |
| 63 | + success = false; |
| 64 | + errorOutput += |
| 65 | + "tspconfig.yaml must define the following property:\n" + |
| 66 | + "\n" + |
| 67 | + "linter:\n" + |
| 68 | + " extends:\n" + |
| 69 | + ` - "${requiredRuleset}"`; |
| 70 | + } |
| 71 | + |
| 72 | + return { |
| 73 | + success: success, |
| 74 | + stdOutput: stdOutput, |
| 75 | + errorOutput: errorOutput, |
| 76 | + }; |
| 77 | + } |
| 78 | +} |
0 commit comments