11import fs from 'node:fs/promises' ;
22import { execSync } from 'child_process' ;
33import path from 'path' ;
4+ import http from 'http' ;
5+ import https from 'https' ;
46
57async function filterIpaViolations ( ) {
68 try {
79 // Check if rule ID is provided
810 const ruleId = process . argv [ 2 ] ;
911 if ( ! ruleId ) {
10- console . error ( 'Usage: node filter-ipa-violations.js <rule-id>' ) ;
12+ console . error ( 'Usage: node filter-ipa-violations.js <rule-id> [remote-openapi-url] ' ) ;
1113 console . error ( 'Example: node filter-ipa-violations.js xgen-IPA-102-collection-identifier-camelCase' ) ;
14+ console . error (
15+ 'Example with remote file: node filter-ipa-violations.js xgen-IPA-102-collection-identifier-camelCase https://raw.githubusercontent.com/mongodb/openapi/refs/heads/dev/openapi/.raw/v2.yaml'
16+ ) ;
1217 process . exit ( 1 ) ;
1318 }
1419
20+ // Check if a remote OpenAPI file URL is provided
21+ const remoteUrl = process . argv [ 3 ] ;
1522 const outputFile = path . join ( process . cwd ( ) , `${ ruleId } -violations.md` ) ;
1623
1724 console . log ( `Filtering violations for rule ID: ${ ruleId } ` ) ;
1825 console . log ( 'Running IPA validation...' ) ;
1926
27+ // If remote URL provided, download it to a temp file
28+ let openapiFilePath = './openapi/.raw/v2.yaml' ; // Default local file
29+ let tempFile = null ;
30+
31+ if ( remoteUrl ) {
32+ console . log ( `Using remote OpenAPI file: ${ remoteUrl } ` ) ;
33+ tempFile = path . join ( process . cwd ( ) , 'temp_openapi_file.yaml' ) ;
34+ await downloadFile ( remoteUrl , tempFile ) ;
35+ openapiFilePath = tempFile ;
36+ } else {
37+ console . log ( 'Using local OpenAPI file' ) ;
38+ }
39+
2040 let validationOutput ;
2141 try {
2242 // Run IPA validation and get output as JSON
2343 execSync (
24- ' spectral lint --format=json -o results.json ./openapi/.raw/v2.yaml --ruleset=./tools/spectral/ipa/ipa-spectral.yaml' ,
44+ ` spectral lint --format=json -o results.json ${ openapiFilePath } --ruleset=./tools/spectral/ipa/ipa-spectral.yaml` ,
2545 {
2646 encoding : 'utf-8' ,
2747 timeout : 4000 ,
@@ -30,6 +50,15 @@ async function filterIpaViolations() {
3050 ) ;
3151 } catch ( error ) {
3252 console . error ( 'Error (expected):' , error . message ) ;
53+ } finally {
54+ // Clean up temp file if it exists
55+ if ( tempFile ) {
56+ try {
57+ await fs . unlink ( tempFile ) ;
58+ } catch ( err ) {
59+ console . error ( 'Error removing temporary file:' , err . message ) ;
60+ }
61+ }
3362 }
3463
3564 // Read the JSON output
@@ -59,12 +88,11 @@ async function filterIpaViolations() {
5988 // Generate markdown content
6089 let markdownContent = `# ${ ruleId } Violations Checklist\n\n` ;
6190 markdownContent += `Generated on: ${ new Date ( ) . toLocaleString ( ) } \n\n` ;
62-
6391 Object . keys ( groupedBySource ) . forEach ( ( source ) => {
6492 const violations = groupedBySource [ source ] ;
6593
6694 violations . forEach ( ( violation ) => {
67- markdownContent += `## ${ violation . source } \n\n` ;
95+ markdownContent += `## ${ violation . message } \n\n` ;
6896 markdownContent += `Path: \`${ violation . path . join ( '/' ) } \`\n\n` ;
6997 markdownContent += `- [ ] Fixed\n\n` ;
7098 } ) ;
@@ -82,4 +110,34 @@ async function filterIpaViolations() {
82110 }
83111}
84112
113+ // Function to download a file from a URL
114+ function downloadFile ( url , outputPath ) {
115+ return new Promise ( ( resolve , reject ) => {
116+ const client = url . startsWith ( 'https' ) ? https : http ;
117+
118+ console . log ( `Downloading OpenAPI file from ${ url } ...` ) ;
119+
120+ const request = client . get ( url , ( response ) => {
121+ if ( response . statusCode < 200 || response . statusCode >= 300 ) {
122+ return reject ( new Error ( `Failed to download file, status code: ${ response . statusCode } ` ) ) ;
123+ }
124+
125+ const file = fs . open ( outputPath , 'w' ) . then ( ( fileHandle ) => fileHandle . createWriteStream ( ) ) ;
126+ file
127+ . then ( ( fileStream ) => {
128+ response . pipe ( fileStream ) ;
129+ response . on ( 'end' , ( ) => {
130+ console . log ( 'Download complete' ) ;
131+ resolve ( ) ;
132+ } ) ;
133+ } )
134+ . catch ( reject ) ;
135+ } ) ;
136+
137+ request . on ( 'error' , ( err ) => {
138+ reject ( err ) ;
139+ } ) ;
140+ } ) ;
141+ }
142+
85143filterIpaViolations ( ) ;
0 commit comments