diff --git a/packages/salesforcedx-vscode-apex/package.json b/packages/salesforcedx-vscode-apex/package.json index e102010015..8aca3448b4 100644 --- a/packages/salesforcedx-vscode-apex/package.json +++ b/packages/salesforcedx-vscode-apex/package.json @@ -139,12 +139,20 @@ { "command": "sf.create.apex.action.class", "when": "sf:project_opened && sf:has_target_org && resource =~ /.\\.(cls)?$/ && salesforcedx-einstein-gpt.isEnabled" + }, + { + "command": "sf.validate.oas.document", + "when": "sf:project_opened && sf:has_target_org && (resource =~ /.\\.(xml)?$/ || resource =~ /.\\.(yaml)?$/) && salesforcedx-einstein-gpt.isEnabled" } ], "explorer/context": [ { "command": "sf.create.apex.action.class", "when": "sf:project_opened && sf:has_target_org && resource =~ /.\\.(cls)?$/ && resourcePath =~ /classes/ && salesforcedx-einstein-gpt.isEnabled" + }, + { + "command": "sf.validate.oas.document", + "when": "sf:project_opened && sf:has_target_org && (resource =~ /.\\.externalServiceRegistration-meta\\.(xml)?$/ || resource =~ /.\\.(yaml)?$/) && salesforcedx-einstein-gpt.isEnabled" } ], "view/title": [ @@ -264,6 +272,10 @@ { "command": "sf.create.apex.action.class", "when": "sf:project_opened && sf:has_target_org && resource =~ /.\\.(cls)?$/ && resourcePath =~ /classes/ && salesforcedx-einstein-gpt.isEnabled" + }, + { + "command": "sf.validate.oas.document", + "when": "sf:project_opened && sf:has_target_org && (resource =~ /.\\.externalServiceRegistration-meta\\.(xml)?$/ || resource =~ /.\\.(yaml)?$/) && salesforcedx-einstein-gpt.isEnabled" } ] }, @@ -375,6 +387,10 @@ { "command": "sf.create.apex.action.class", "title": "%create_openapi_doc_class%" + }, + { + "command": "sf.validate.oas.document", + "title": "%validate_oas_document%" } ], "configuration": { diff --git a/packages/salesforcedx-vscode-apex/package.nls.ja.json b/packages/salesforcedx-vscode-apex/package.nls.ja.json index e5d737ad83..20bf2c1021 100644 --- a/packages/salesforcedx-vscode-apex/package.nls.ja.json +++ b/packages/salesforcedx-vscode-apex/package.nls.ja.json @@ -22,6 +22,7 @@ "collapse_tests_title": "SFDX: Apex テストを隠す", "create_openapi_doc_method": "SFDX: Create OpenAPI Document from Selected Method", "create_openapi_doc_class": "SFDX: Create OpenAPI Document from This Class (Beta)", + "validate_oas_document": "SFDX: Validate OpenAPI Document (Beta)", "enable-apex-ls-error-to-telemetry": "Allow the Apex Language Server to collect telemetry of errors", "go_to_definition_title": "定義に移動", "java_home_description": "Specifies the folder path to the Java 11, Java 17, or Java 21 runtime used to launch the Apex Language Server. Note on Windows the backslashes must be escaped.\n\nMac Example: `/Library/Java/JavaVirtualMachines/openjdk-11.jdk/Contents/Home`\n\nWindows Example: `C:\\\\Program Files\\\\Zulu\\\\zulu-17`\n\nLinux Example: `/usr/lib/jvm/java-21-openjdk-amd64`", diff --git a/packages/salesforcedx-vscode-apex/package.nls.json b/packages/salesforcedx-vscode-apex/package.nls.json index 3c98ec148e..bb035b910b 100644 --- a/packages/salesforcedx-vscode-apex/package.nls.json +++ b/packages/salesforcedx-vscode-apex/package.nls.json @@ -24,6 +24,7 @@ "collapse_tests_title": "SFDX: Collapse All Apex Tests", "create_openapi_doc_method": "SFDX: Create OpenAPI Document from Selected Method", "create_openapi_doc_class": "SFDX: Create OpenAPI Document from This Class (Beta)", + "validate_oas_document": "SFDX: Validate OpenAPI Document (Beta)", "enable-apex-ls-error-to-telemetry": "Allow the Apex Language Server to collect telemetry of errors", "go_to_definition_title": "Go to Definition", "java_home_description": "Specifies the folder path to the Java 11, Java 17, or Java 21 runtime used to launch the Apex Language Server. Note on Windows the backslashes must be escaped.\n\nMac Example: `/Library/Java/JavaVirtualMachines/openjdk-11.jdk/Contents/Home`\n\nWindows Example: `C:\\\\Program Files\\\\Zulu\\\\zulu-17`\n\nLinux Example: `/usr/lib/jvm/java-21-openjdk-amd64`", diff --git a/packages/salesforcedx-vscode-apex/src/commands/apexActionController.ts b/packages/salesforcedx-vscode-apex/src/commands/apexActionController.ts index 31d086c795..9d61fc7615 100644 --- a/packages/salesforcedx-vscode-apex/src/commands/apexActionController.ts +++ b/packages/salesforcedx-vscode-apex/src/commands/apexActionController.ts @@ -5,7 +5,6 @@ * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ -import { SfProject } from '@salesforce/core-bundle'; import { notificationService, WorkspaceContextUtil, workspaceUtils } from '@salesforce/salesforcedx-utils-vscode'; import { RegistryAccess } from '@salesforce/source-deploy-retrieve-bundle'; import { XMLBuilder, XMLParser } from 'fast-xml-parser'; @@ -13,26 +12,21 @@ import * as fs from 'fs'; import { OpenAPIV3 } from 'openapi-types'; import * as path from 'path'; import * as vscode from 'vscode'; -import { parse, stringify } from 'yaml'; +import { stringify } from 'yaml'; import { workspaceContext } from '../context'; import { nls } from '../messages'; -import { OasProcessor } from '../oas/documentProcessorPipeline/oasProcessor'; import { BidRule, PromptGenerationOrchestrator } from '../oas/promptGenerationOrchestrator'; -import { - ApexClassOASEligibleResponse, - ApexClassOASGatherContextResponse, - ApexOASInfo, - ExternalServiceOperation -} from '../oas/schemas'; +import { ApexOASInfo, ExternalServiceOperation } from '../oas/schemas'; import { getTelemetryService } from '../telemetry/telemetry'; import { MetadataOrchestrator } from './metadataOrchestrator'; +import { checkIfESRIsDecomposed, createProblemTabEntriesForOasDocument, processOasDocument } from './oasUtils'; export class ApexActionController { private isESRDecomposed: boolean = false; constructor(private metadataOrchestrator: MetadataOrchestrator) {} public async initialize(extensionContext: vscode.ExtensionContext) { await WorkspaceContextUtil.getInstance().initialize(extensionContext); - this.isESRDecomposed = await this.checkIfESRIsDecomposed(); + this.isESRDecomposed = await checkIfESRIsDecomposed(); } /** @@ -88,13 +82,13 @@ export class ApexActionController { ); // Step 7: Process the OAS document - const processedOasDoc = await this.processOasDocument(openApiDocument, context, eligibilityResult); + const processedOasResult = await processOasDocument(openApiDocument, context, eligibilityResult); // Step 8: Write OpenAPI Document to File progress.report({ message: nls.localize('write_openapi_document') }); - await this.saveOasAsEsrMetadata(processedOasDoc, fullPath[1]); + await this.saveOasAsEsrMetadata(processedOasResult.yaml, fullPath[1]); - // Step 7: If the user chose to merge, open a diff between the original and new ESR files + // Step 9: If the user chose to merge, open a diff between the original and new ESR files if (fullPath[0] !== fullPath[1]) { void this.openDiffFile(fullPath[0], fullPath[1], 'Manual Diff of ESR XML Files'); @@ -108,7 +102,14 @@ export class ApexActionController { } } - // Step 8: Call Mulesoft extension if installed + // Step: 10 Create entries in problems tab for generated file + createProblemTabEntriesForOasDocument( + this.isESRDecomposed ? this.replaceXmlToYaml(fullPath[0]) : fullPath[0], + processedOasResult, + this.isESRDecomposed + ); + + // Step 11: Call Mulesoft extension if installed const callMulesoftExtension = async () => { if (await this.isCommandAvailable('mule-dx-api.open-api-project')) { try { @@ -149,17 +150,6 @@ export class ApexActionController { } }; - private processOasDocument = async ( - oasDoc: string, - context: ApexClassOASGatherContextResponse, - eligibleResult: ApexClassOASEligibleResponse - ): Promise => { - const parsed = parse(oasDoc); - const oasProcessor = new OasProcessor(context, parsed, eligibleResult); - const processResult = await oasProcessor.process(); - return processResult.yaml; - }; - /** * Handles errors by showing a notification and sending telemetry data. * @param error - The error to handle. @@ -468,21 +458,6 @@ export class ApexActionController { return operations.filter((operation): operation is ExternalServiceOperation => operation !== null); }; - /** - * Reads sfdx-project.json and checks if decomposeExternalServiceRegistrationBeta is enabled. - * @returns boolean - true if sfdx-project.json contains decomposeExternalServiceRegistrationBeta - */ - private checkIfESRIsDecomposed = async (): Promise => { - const projectPath = workspaceUtils.getRootWorkspacePath(); - const sfProject = await SfProject.resolve(projectPath); - const sfdxProjectJson = sfProject.getSfProjectJson(); - if (sfdxProjectJson.getContents().sourceBehaviorOptions?.includes('decomposeExternalServiceRegistrationBeta')) { - return true; - } - - return false; - }; - /** * Builds the YAML file for the ESR using safeOasSpec as the contents. * @param esrXmlPath - The path to the ESR XML file. diff --git a/packages/salesforcedx-vscode-apex/src/commands/index.ts b/packages/salesforcedx-vscode-apex/src/commands/index.ts index 41115de4ea..f4d666da32 100644 --- a/packages/salesforcedx-vscode-apex/src/commands/index.ts +++ b/packages/salesforcedx-vscode-apex/src/commands/index.ts @@ -19,4 +19,5 @@ export { } from './apexTestRunCodeAction'; export { apexTestSuiteAdd, apexTestSuiteCreate, apexTestSuiteRun } from './apexTestSuite'; export { createApexActionFromMethod, createApexActionFromClass } from './createApexAction'; +export { validateOpenApiDocument } from './oasDocumentChecker'; export { launchApexReplayDebuggerWithCurrentFile } from './launchApexReplayDebuggerWithCurrentFile'; diff --git a/packages/salesforcedx-vscode-apex/src/commands/oasDocumentChecker.ts b/packages/salesforcedx-vscode-apex/src/commands/oasDocumentChecker.ts new file mode 100644 index 0000000000..47920112ed --- /dev/null +++ b/packages/salesforcedx-vscode-apex/src/commands/oasDocumentChecker.ts @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2025, salesforce.com, inc. + * All rights reserved. + * Licensed under the BSD 3-Clause license. + * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause + */ +import { notificationService, WorkspaceContextUtil } from '@salesforce/salesforcedx-utils-vscode'; +import { XMLParser } from 'fast-xml-parser'; +import * as fs from 'fs'; +import * as path from 'path'; +import * as vscode from 'vscode'; +import { nls } from '../messages'; +import { getTelemetryService } from '../telemetry/telemetry'; +import { checkIfESRIsDecomposed, createProblemTabEntriesForOasDocument, processOasDocument } from './oasUtils'; +// This class runs the validation and correction logic on Oas Documents +export class OasDocumentChecker { + private isESRDecomposed: boolean = false; + private static _instance: OasDocumentChecker; + + private constructor() {} + + public static get Instance() { + // Do you need arguments? Make it a regular static method instead. + return this._instance || (this._instance = new this()); + } + + public async initialize(extensionContext: vscode.ExtensionContext) { + await WorkspaceContextUtil.getInstance().initialize(extensionContext); + this.isESRDecomposed = await checkIfESRIsDecomposed(); + } + + /** + * Validates an OpenAPI Document. + * @param isClass - Indicates if the action is for a class or a method. + */ + public validateOasDocument = async (sourceUri: vscode.Uri | vscode.Uri[]): Promise => { + try { + await vscode.window.withProgress( + { + location: vscode.ProgressLocation.Notification, + title: 'SFDX: Running validations on OAS Document', + cancellable: true + }, + async () => { + if (Array.isArray(sourceUri)) { + throw nls.localize('invalid_file_for_generating_oas_doc'); + } + + const fullPath = sourceUri ? sourceUri.fsPath : vscode.window.activeTextEditor?.document.uri.fsPath || ''; + + // Step 1: Validate eligibility + if (!this.isFilePathEligible(fullPath)) { + throw nls.localize('invalid_file_for_generating_oas_doc'); + } + // Step 2: Extract openAPI document if embedded inside xml + let openApiDocument: string; + if (fullPath.endsWith('.xml')) { + const xmlContent = fs.readFileSync(fullPath, 'utf8'); + const parser = new XMLParser(); + const jsonObj = parser.parse(xmlContent); + openApiDocument = jsonObj.ExternalServiceRegistration?.schema; + } else { + openApiDocument = fs.readFileSync(fullPath, 'utf8'); + } + // Step 3: Process the OAS document + const processedOasResult = await processOasDocument(openApiDocument, undefined, undefined, true); + + // Step 4: Report/Refresh problems found + createProblemTabEntriesForOasDocument(fullPath, processedOasResult, this.isESRDecomposed); + + const telemetryService = await getTelemetryService(); + // Step 5: Notify Success + notificationService.showInformationMessage( + nls.localize('check_openapi_doc_succeeded', path.basename(fullPath)) + ); + telemetryService.sendEventData('OasValidationSucceeded'); + } + ); + } catch (error: any) { + void this.handleError(error, 'OasValidationFailed'); + } + }; + + /** + * Handles errors by showing a notification and sending telemetry data. + * @param error - The error to handle. + * @param telemetryEvent - The telemetry event name. + */ + private handleError = async (error: any, telemetryEvent: string): Promise => { + const telemetryService = await getTelemetryService(); + const errorMessage = error instanceof Error ? error.message : String(error); + notificationService.showErrorMessage(`${nls.localize('check_openapi_doc_failed')}: ${errorMessage}`); + telemetryService.sendException(telemetryEvent, errorMessage); + }; + + private isFilePathEligible = (fullPath: string): boolean => { + // check if yaml or xml, else return false + if (!(fullPath.endsWith('.yaml') || fullPath.endsWith('.externalServiceRegistration-meta.xml'))) { + return false; + } + + // if xml, check registrationProviderType to be ApexRest + if (fullPath.endsWith('.xml')) { + const xmlContent = fs.readFileSync(fullPath, 'utf8'); + const parser = new XMLParser(); + const jsonObj = parser.parse(xmlContent); + const registrationProviderType = jsonObj.ExternalServiceRegistration?.registrationProviderType; + if (registrationProviderType === 'Custom' || registrationProviderType === 'ApexRest') { + return true; + } + } + + // if yaml, find the associated xml and look for registrationProviderType to be ApexRest + if (fullPath.endsWith('.yaml')) { + // check folder in which the file is present + const className = path.basename(fullPath).split('.')[0]; + const dirName = path.dirname(fullPath); + const associatedXmlFileName = `${className}.externalServiceRegistration-meta.xml`; + + const xmlContent = fs.readFileSync(path.join(dirName, associatedXmlFileName), 'utf8'); + const parser = new XMLParser(); + const jsonObj = parser.parse(xmlContent); + const registrationProviderType = jsonObj.ExternalServiceRegistration?.registrationProviderType; + if (registrationProviderType === 'Custom' || registrationProviderType === 'ApexRest') { + return true; + } + } + + return false; + }; +} + +export const validateOpenApiDocument = async (sourceUri: vscode.Uri | vscode.Uri[]): Promise => { + const oasDocumentChecker = OasDocumentChecker.Instance; + await oasDocumentChecker.validateOasDocument(sourceUri); +}; diff --git a/packages/salesforcedx-vscode-apex/src/commands/oasUtils.ts b/packages/salesforcedx-vscode-apex/src/commands/oasUtils.ts new file mode 100644 index 0000000000..df4ea4267c --- /dev/null +++ b/packages/salesforcedx-vscode-apex/src/commands/oasUtils.ts @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2025, salesforce.com, inc. + * All rights reserved. + * Licensed under the BSD 3-Clause license. + * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause + */ + +import { SfProject } from '@salesforce/core-bundle'; +import { workspaceUtils } from '@salesforce/salesforcedx-utils-vscode'; +import * as vscode from 'vscode'; +import { parse } from 'yaml'; +import { nls } from '../messages'; +import OasProcessor from '../oas/documentProcessorPipeline'; +import { ProcessorInputOutput } from '../oas/documentProcessorPipeline/processorStep'; +import { ApexClassOASGatherContextResponse, ApexClassOASEligibleResponse } from '../oas/schemas'; + +export const processOasDocument = async ( + oasDoc: string, + context?: ApexClassOASGatherContextResponse, + eligibleResult?: ApexClassOASEligibleResponse, + isRevalidation?: boolean +): Promise => { + if (isRevalidation || context?.classDetail.annotations.find(a => a.name === 'RestResource')) { + const parsed = parse(oasDoc); + const oasProcessor = new OasProcessor(parsed, eligibleResult); + + const processResult = await oasProcessor.process(); + + return processResult; + } + throw nls.localize('invalid_file_for_generating_oas_doc'); +}; + +export const createProblemTabEntriesForOasDocument = ( + fullPath: string, + processedOasResult: ProcessorInputOutput, + isESRDecomposed: boolean +) => { + const uri = vscode.Uri.parse(fullPath); + OasProcessor.diagnosticCollection.clear(); + + const adjustErrors = processedOasResult.errors.map(result => { + // if embedded inside of ESR.xml then position is hardcoded because of `apexActionController.createESRObject` + const lineAdjustment = isESRDecomposed ? 0 : 4; + const startCharacterAdjustment = isESRDecomposed ? 0 : 11; + const range = new vscode.Range( + result.range.start.line + lineAdjustment, + result.range.start.character + result.range.start.line <= 1 ? startCharacterAdjustment : 0, + result.range.end.line + lineAdjustment, + result.range.end.character + result.range.start.line <= 1 ? startCharacterAdjustment : 0 + ); + + return new vscode.Diagnostic(range, result.message, result.severity); + }); + OasProcessor.diagnosticCollection.set(uri, adjustErrors); +}; + +/** + * Reads sfdx-project.json and checks if decomposeExternalServiceRegistrationBeta is enabled. + * @returns boolean - true if sfdx-project.json contains decomposeExternalServiceRegistrationBeta + */ +export const checkIfESRIsDecomposed = async (): Promise => { + const projectPath = workspaceUtils.getRootWorkspacePath(); + const sfProject = await SfProject.resolve(projectPath); + const sfdxProjectJson = sfProject.getSfProjectJson(); + if (sfdxProjectJson.getContents().sourceBehaviorOptions?.includes('decomposeExternalServiceRegistrationBeta')) { + return true; + } + + return false; +}; diff --git a/packages/salesforcedx-vscode-apex/src/index.ts b/packages/salesforcedx-vscode-apex/src/index.ts index f3fcf3c908..76f48ed4f7 100644 --- a/packages/salesforcedx-vscode-apex/src/index.ts +++ b/packages/salesforcedx-vscode-apex/src/index.ts @@ -27,6 +27,7 @@ import { apexTestSuiteRun, createApexActionFromMethod, createApexActionFromClass, + validateOpenApiDocument, launchApexReplayDebuggerWithCurrentFile, ApexActionController } from './commands'; @@ -171,6 +172,10 @@ const registerCommands = (): vscode.Disposable => { 'sf.create.apex.action.class', createApexActionFromClass ); + const validateOpenApiDocumentCmd = vscode.commands.registerCommand( + 'sf.validate.oas.document', + validateOpenApiDocument + ); const launchApexReplayDebuggerWithCurrentFileCmd = vscode.commands.registerCommand( 'sf.launch.apex.replay.debugger.with.current.file', launchApexReplayDebuggerWithCurrentFile @@ -198,6 +203,7 @@ const registerCommands = (): vscode.Disposable => { apexTestSuiteAddCmd, createApexActionFromMethodCmd, createApexActionFromClassCmd, + validateOpenApiDocumentCmd, launchApexReplayDebuggerWithCurrentFileCmd ); }; diff --git a/packages/salesforcedx-vscode-apex/src/messages/i18n.ja.ts b/packages/salesforcedx-vscode-apex/src/messages/i18n.ja.ts index 2a7e1a162b..8b46d54adc 100644 --- a/packages/salesforcedx-vscode-apex/src/messages/i18n.ja.ts +++ b/packages/salesforcedx-vscode-apex/src/messages/i18n.ja.ts @@ -110,6 +110,8 @@ export const messages = { no_oas_generated: 'LLM did not return any content.', failed_to_combine_oas: 'Failed to combine yaml docs', strategy_not_qualified: 'No generation strategy is qualified for the selected class or method.', - invalid_class_annotation_for_generating_oas_doc: 'Invalid class annotation for generating OAS doc', - cleanup_yaml_failed: 'Could not find openapi line in document:\n' + invalid_file_for_generating_oas_doc: 'Invalid file for generating OAS doc', + cleanup_yaml_failed: 'Could not find openapi line in document:\n', + check_openapi_doc_failed: 'Failed to check OpenAPI Document', + check_openapi_doc_succeeded: 'Validated the OpenAPI Document successfully' }; diff --git a/packages/salesforcedx-vscode-apex/src/messages/i18n.ts b/packages/salesforcedx-vscode-apex/src/messages/i18n.ts index 7d7c4bcd0f..1699482f95 100644 --- a/packages/salesforcedx-vscode-apex/src/messages/i18n.ts +++ b/packages/salesforcedx-vscode-apex/src/messages/i18n.ts @@ -131,11 +131,13 @@ export const messages = { no_oas_generated: 'LLM did not return any content.', failed_to_combine_oas: 'Failed to combine yaml docs', strategy_not_qualified: 'No generation strategy is qualified for the selected class or method.', - invalid_class_annotation_for_generating_oas_doc: 'Invalid class annotation for generating OAS doc', + invalid_file_for_generating_oas_doc: 'Invalid file for generating OAS doc', no_eligible_method: 'No eligible methods found in the class', failed_to_parse_yaml: 'Failed to parse the document as YAML: %s', ineligible_method_in_doc: 'Method %s is not eligible for OAS generation, but present in the document', eligible_method_not_in_doc: 'Methods %s are eligible for OAS generation, but not present in the document', method_not_found_in_doc_symbols: 'Method %s is not found in the document symbols', - cleanup_yaml_failed: 'Could not find openapi line in document:\n' + cleanup_yaml_failed: 'Could not find openapi line in document:\n', + check_openapi_doc_failed: 'Failed to check OpenAPI Document', + check_openapi_doc_succeeded: 'Validated OpenAPI Document %s successfully' }; diff --git a/packages/salesforcedx-vscode-apex/src/oas/documentProcessorPipeline/methodValidationStep.ts b/packages/salesforcedx-vscode-apex/src/oas/documentProcessorPipeline/methodValidationStep.ts index d8c9468de0..be0362f468 100644 --- a/packages/salesforcedx-vscode-apex/src/oas/documentProcessorPipeline/methodValidationStep.ts +++ b/packages/salesforcedx-vscode-apex/src/oas/documentProcessorPipeline/methodValidationStep.ts @@ -16,16 +16,16 @@ import { ProcessorInputOutput, ProcessorStep } from './processorStep'; export class MethodValidationStep implements ProcessorStep { static diagnosticCollection: vscode.DiagnosticCollection = vscode.languages.createDiagnosticCollection('OAS Method Validations'); - private className: string = ''; - private virtualUri: vscode.Uri | null = null; // the url of the virtual YAML file private diagnostics: vscode.Diagnostic[] = []; constructor() {} process(input: ProcessorInputOutput): Promise { - this.className = input.context.classDetail.name as string; - this.virtualUri = vscode.Uri.parse(`untitled:${this.className}_OAS_temp.yaml`); + if (!input.eligibilityResult) { + console.log('skipping methodValidationStep as no eligibility results passed'); + return Promise.resolve(input); + } + MethodValidationStep.diagnosticCollection.clear(); const cleanedupYaml = this.validateMethods(input.yaml, input.eligibilityResult); - MethodValidationStep.diagnosticCollection.set(this.virtualUri, this.diagnostics); input.errors = [...input.errors, ...this.diagnostics]; return new Promise(resolve => { resolve({ ...input, yaml: cleanedupYaml }); diff --git a/packages/salesforcedx-vscode-apex/src/oas/documentProcessorPipeline/oasProcessor.ts b/packages/salesforcedx-vscode-apex/src/oas/documentProcessorPipeline/oasProcessor.ts index e0d444b0e6..8caaf86c47 100644 --- a/packages/salesforcedx-vscode-apex/src/oas/documentProcessorPipeline/oasProcessor.ts +++ b/packages/salesforcedx-vscode-apex/src/oas/documentProcessorPipeline/oasProcessor.ts @@ -6,8 +6,8 @@ */ import { OpenAPIV3 } from 'openapi-types'; -import { nls } from '../../messages'; -import { ApexClassOASEligibleResponse, ApexClassOASGatherContextResponse } from '../schemas'; +import * as vscode from 'vscode'; +import { ApexClassOASEligibleResponse } from '../schemas'; import { MethodValidationStep } from './methodValidationStep'; import { OasValidationStep } from './oasValidationStep'; import { Pipeline } from './pipeline'; @@ -16,39 +16,29 @@ import { PropertyCorrectionStep } from './propertyCorrectionStep'; import { ReconcileDuplicateSemanticPathsStep } from './reconcileDuplicateSemanticPathsStep'; export class OasProcessor { - private context: ApexClassOASGatherContextResponse; private document: OpenAPIV3.Document; - private eligibilityResult: ApexClassOASEligibleResponse; - constructor( - context: ApexClassOASGatherContextResponse, - document: OpenAPIV3.Document, - eligibilityResult: ApexClassOASEligibleResponse - ) { - this.context = context; + private eligibilityResult?: ApexClassOASEligibleResponse; + static diagnosticCollection: vscode.DiagnosticCollection = + vscode.languages.createDiagnosticCollection('OAS Validations'); + constructor(document: OpenAPIV3.Document, eligibilityResult?: ApexClassOASEligibleResponse) { this.document = document; this.eligibilityResult = eligibilityResult; } async process(): Promise { - if (this.context.classDetail.annotations.find(a => a.name === 'RestResource')) { - // currently only OasValidation exists, in future this would have converters too - const pipeline = new Pipeline(new PropertyCorrectionStep()) - .addStep(new ReconcileDuplicateSemanticPathsStep()) - .addStep(new MethodValidationStep()) - .addStep(new OasValidationStep(this.context.classDetail.name)); + const pipeline = new Pipeline(new PropertyCorrectionStep()) + .addStep(new ReconcileDuplicateSemanticPathsStep()) + .addStep(new MethodValidationStep()) + .addStep(new OasValidationStep()); - console.log('Executing pipeline with input:'); - console.log('context: ', JSON.stringify(this.context)); - console.log('document: ', this.document); - const output = await pipeline.execute({ - yaml: this.document, - errors: [], - eligibilityResult: this.eligibilityResult, - context: this.context - }); - console.log('Pipeline output:', output); - return output; - } - throw nls.localize('invalid_class_annotation_for_generating_oas_doc'); + console.log('Executing pipeline with input:'); + console.log('document: ', this.document); + const output = await pipeline.execute({ + yaml: this.document, + errors: [], + eligibilityResult: this.eligibilityResult + }); + console.log('Pipeline output:', output); + return output; } } diff --git a/packages/salesforcedx-vscode-apex/src/oas/documentProcessorPipeline/oasValidationStep.ts b/packages/salesforcedx-vscode-apex/src/oas/documentProcessorPipeline/oasValidationStep.ts index 585e777d9a..13e99df8a9 100644 --- a/packages/salesforcedx-vscode-apex/src/oas/documentProcessorPipeline/oasValidationStep.ts +++ b/packages/salesforcedx-vscode-apex/src/oas/documentProcessorPipeline/oasValidationStep.ts @@ -12,23 +12,10 @@ import { ProcessorInputOutput, ProcessorStep } from './processorStep'; import ruleset from './ruleset.spectral'; export class OasValidationStep implements ProcessorStep { - public static diagnosticCollection: vscode.DiagnosticCollection = - vscode.languages.createDiagnosticCollection('OAS Validations'); - private className: string; - - constructor(className: string) { - // Initialize a diagnostic collection for in-memory YAML validation - this.className = className; - } - async process(input: ProcessorInputOutput): Promise { const spectral = new Spectral(); spectral.setRuleset(ruleset); - // Create a virtual URI to represent the YAML - const virtualUri = vscode.Uri.parse(`untitled:${this.className}_OAS_temp.yaml`); - OasValidationStep.diagnosticCollection.clear(); - // Run validation using Spectral await spectral.run(stringify(input.yaml)).then(results => { const diagnostics: vscode.Diagnostic[] = results.map(result => { @@ -42,8 +29,6 @@ export class OasValidationStep implements ProcessorStep { return new vscode.Diagnostic(range, result.message, this.mapSeverity(result.severity)); }); - // Add diagnostics to the Problems tab for the virtual document - OasValidationStep.diagnosticCollection.set(virtualUri, diagnostics); input.errors = [...input.errors, ...diagnostics]; }); diff --git a/packages/salesforcedx-vscode-apex/src/oas/documentProcessorPipeline/processorStep.ts b/packages/salesforcedx-vscode-apex/src/oas/documentProcessorPipeline/processorStep.ts index af6721f87b..f348357879 100644 --- a/packages/salesforcedx-vscode-apex/src/oas/documentProcessorPipeline/processorStep.ts +++ b/packages/salesforcedx-vscode-apex/src/oas/documentProcessorPipeline/processorStep.ts @@ -11,8 +11,7 @@ import { ApexClassOASEligibleResponse, ApexClassOASGatherContextResponse } from export interface ProcessorInputOutput { yaml: OpenAPIV3.Document; errors: vscode.Diagnostic[]; - readonly eligibilityResult: ApexClassOASEligibleResponse; - readonly context: ApexClassOASGatherContextResponse; + readonly eligibilityResult?: ApexClassOASEligibleResponse; } export interface ProcessorStep {