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
@@ -82,4 +111,34 @@ async function filterIpaViolations() {
82111 }
83112}
84113
114+ // Function to download a file from a URL
115+ function downloadFile ( url , outputPath ) {
116+ return new Promise ( ( resolve , reject ) => {
117+ const client = url . startsWith ( 'https' ) ? https : http ;
118+
119+ console . log ( `Downloading OpenAPI file from ${ url } ...` ) ;
120+
121+ const request = client . get ( url , ( response ) => {
122+ if ( response . statusCode < 200 || response . statusCode >= 300 ) {
123+ return reject ( new Error ( `Failed to download file, status code: ${ response . statusCode } ` ) ) ;
124+ }
125+
126+ const file = fs . open ( outputPath , 'w' ) . then ( ( fileHandle ) => fileHandle . createWriteStream ( ) ) ;
127+ file
128+ . then ( ( fileStream ) => {
129+ response . pipe ( fileStream ) ;
130+ response . on ( 'end' , ( ) => {
131+ console . log ( 'Download complete' ) ;
132+ resolve ( ) ;
133+ } ) ;
134+ } )
135+ . catch ( reject ) ;
136+ } ) ;
137+
138+ request . on ( 'error' , ( err ) => {
139+ reject ( err ) ;
140+ } ) ;
141+ } ) ;
142+ }
143+
85144filterIpaViolations ( ) ;
0 commit comments