Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Madhur/w 17619393 #6017

Merged
merged 6 commits into from
Jan 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/closeStaleIssues.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
steps:
- uses: actions/stale@v9
with:
node-version: '20.9.0'
node-version: '20.17.0'
stale-issue-label: stale
days-before-issue-stale: 3
days-before-issue-close: 2
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/runE2ETest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ jobs:
matrix:
os: ${{ fromJson(inputs.os) }}
nodeVersion:
- 20.9.0
- 20.17.0
vscodeVersion:
- ${{ inputs.vscodeVersion }}
steps:
Expand Down
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v20.9.0
v20.17.0
18,154 changes: 8,845 additions & 9,309 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
"packages/*"
],
"engines": {
"node": ">=20.9.0"
"node": ">=20.17"
},
"dependencies": {
"@actions/core": "^1.11.0",
"@actions/github": "^5.1.1",
"node": "^20.9.0",
"node": "^20.17.0",
"npm": "^10",
"semver": "^7.5.4",
"ts-node": "10.9.2"
Expand All @@ -35,7 +35,7 @@
"@vscode/test-electron": "2.3.0",
"@vscode/vsce": "2.21.1",
"acorn": "8.8.2",
"ajv": "6.12.6",
"ajv": "8.17.1",
peternhale marked this conversation as resolved.
Show resolved Hide resolved
"check-peer-dependencies": "4.1.0",
"commitizen": "^4.2.5",
"cz-conventional-changelog": "3.3.0",
Expand Down
2 changes: 2 additions & 0 deletions packages/salesforcedx-vscode-apex/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
"devDependencies": {
"@salesforce/salesforcedx-test-utils-vscode": "62.14.1",
"@salesforce/ts-sinon": "1.4.0",
"@stoplight/spectral-core": "1.19.4",
"@stoplight/spectral-rulesets": "1.21.3",
"@types/chai": "4.3.3",
"@types/mocha": "^5",
"@types/node": "^20.0.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import * as vscode from 'vscode';
import { parse } from 'yaml';
import { workspaceContext } from '../context';
import { nls } from '../messages';
import { OasProcessor } from '../oas/documentProcessorPipeline/oasProcessor';
import {
ApexClassOASEligibleResponse,
ApexClassOASGatherContextResponse,
Expand Down Expand Up @@ -98,8 +99,11 @@ export class ApexActionController {
const documentText = fs.readFileSync(new URL(metadata.resourceUri.toString()), 'utf8');
const openAPIdocument = await this.metadataOrchestrator.sendPromptToLLM(documentText, context);

// Convert the OpenAPI document to YAML
return this.cleanupYaml(openAPIdocument);
// hand off the validation and correction to processor.
const oasProcessor = new OasProcessor(context, openAPIdocument);
const processorResult = await oasProcessor.process();

return processorResult.yaml;
};

/**
Expand All @@ -114,19 +118,6 @@ export class ApexActionController {
telemetryService.sendException(telemetryEvent, errorMessage);
};

private cleanupYaml(doc: string): string {
// Remove the first line of the document
const openApiIndex = doc.indexOf('openapi');
if (openApiIndex === -1) {
throw new Error('Could not find openapi line in document:\n' + doc);
}
return doc
.substring(openApiIndex)
.split('\n')
.filter(line => !/^```$/.test(line))
.join('\n');
}

private saveOasAsErsMetadata = async (oasSpec: string, fullPath: string): Promise<void> => {
const orgVersion = await (await WorkspaceContextUtil.getInstance().getConnection()).retrieveMaxApiVersion();
// Replace the schema section in the ESR file if it already exists
Expand Down
3 changes: 2 additions & 1 deletion packages/salesforcedx-vscode-apex/src/messages/i18n.ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,5 +103,6 @@ export const messages = {
schema_element_not_found: 'The <schema> element was not found in the provided XML.',
operations_element_not_found: 'The <operations> element was not found in the provided XML.',
error_retrieving_org_version: 'Failed to retrieve org version',
error_parsing_yaml: 'Error parsing YAML'
error_parsing_yaml: 'Error parsing YAML',
invalid_class_annotation_for_generating_oas_doc: 'Invalid class annotation for generating OAS doc'
};
3 changes: 2 additions & 1 deletion packages/salesforcedx-vscode-apex/src/messages/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,5 +123,6 @@ export const messages = {
schema_element_not_found: 'The <schema> element was not found in the provided XML.',
operations_element_not_found: 'The <operations> element was not found in the provided XML.',
error_retrieving_org_version: 'Failed to retrieve org version',
error_parsing_yaml: 'Error parsing YAML'
error_parsing_yaml: 'Error parsing YAML',
invalid_class_annotation_for_generating_oas_doc: 'Invalid class annotation for generating OAS doc'
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* 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 { ProcessorInputOutput, ProcessorStep } from './processorStep';

export class CleanupYamlStep implements ProcessorStep {
process(input: ProcessorInputOutput): Promise<ProcessorInputOutput> {
const cleanedupYaml = this.cleanupYaml(input.yaml);

return new Promise(resolve => {
resolve({ ...input, yaml: cleanedupYaml });
});
}

private cleanupYaml(doc: string): string {
// Remove the first line of the document
const openApiIndex = doc.indexOf('openapi');
if (openApiIndex === -1) {
throw new Error('Could not find openapi line in document:\n' + doc);
}
return doc
.substring(openApiIndex)
.split('\n')
.filter(line => !/^```$/.test(line))
.join('\n');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* 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 { OasProcessor } from './oasProcessor';

export default OasProcessor;
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* 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 { nls } from '../../messages';
import { ApexClassOASGatherContextResponse } from '../../openApiUtilities/schemas';
import { CleanupYamlStep } from './cleanupYamlStep';
import { OasValidationStep } from './oasValidationStep';
import { Pipeline } from './pipeline';
import { ProcessorInputOutput } from './processorStep';

export class OasProcessor {
private context: ApexClassOASGatherContextResponse;
private document: string;

constructor(context: ApexClassOASGatherContextResponse, document: string) {
this.context = context;
this.document = document;
}

async process(): Promise<ProcessorInputOutput> {
if (this.context.classDetail.annotations.includes('RestResource')) {
// currently only OasValidation exists, in future this would have converters too
const pipeline = new Pipeline(new CleanupYamlStep()).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 });
console.log('Pipeline output:', output);
return output;
}
throw nls.localize('invalid_class_annotation_for_generating_oas_doc');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* 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 { Spectral } from '@stoplight/spectral-core';
import { ProcessorInputOutput, ProcessorStep } from './processorStep';
import ruleset from './ruleset.spectral';

export class OasValidationStep implements ProcessorStep {
async process(input: ProcessorInputOutput): Promise<ProcessorInputOutput> {
const spectral = new Spectral();

spectral.setRuleset(ruleset);

// we lint our document using the ruleset
await spectral.run(input.yaml).then(result => {
// the validation should be shown in problems tab, this will be covered by W-17656525
console.log('spectral results:', JSON.stringify(result));
input.errors = result;
});

// Since this step doesn't perform convertions we return the input for future processing
return input;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* 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 { ProcessorInputOutput, ProcessorStep } from './processorStep';

export class Pipeline {
private steps: ProcessorStep[] = [];

constructor(currentStep: ProcessorStep) {
this.steps.push(currentStep);
}

addStep(newStep: ProcessorStep) {
this.steps.push(newStep);
return this;
}

async execute(input: ProcessorInputOutput) {
let output: ProcessorInputOutput = input;
for (const step of this.steps) {
output = await step.process(output);
}
return output;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* 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 { ISpectralDiagnostic } from '@stoplight/spectral-core';

export interface ProcessorInputOutput {
yaml: string;
errors?: ISpectralDiagnostic[];
}

export interface ProcessorStep {
process(input: ProcessorInputOutput): Promise<ProcessorInputOutput>;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* 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 { oas } from '@stoplight/spectral-rulesets';

const ruleset = {
extends: [oas],
rules: {}
};

export default ruleset;
2 changes: 1 addition & 1 deletion packages/salesforcedx-vscode-lwc/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"@salesforce/lightning-lsp-common": "4.12.2",
"@salesforce/lwc-language-server": "4.12.2",
"@salesforce/salesforcedx-utils-vscode": "62.14.1",
"ajv": "6.12.6",
"ajv": "8.17.1",
"applicationinsights": "1.0.7",
"jest-editor-support": "30.3.1",
"jest-regex-util": "^24.9.0",
Expand Down
Loading