1
1
const { execFileSync, spawnSync } = require ( 'child_process' ) ;
2
- const { existsSync, readFileSync, statSync , writeFileSync } = require ( 'fs' ) ;
2
+ const { existsSync, readdirSync , readFileSync, renameSync , statSync } = require ( 'fs' ) ;
3
3
const { arch, platform } = require ( 'os' ) ;
4
- const { dirname, join, resolve } = require ( 'path' ) ;
4
+ const { dirname, format , join, parse , resolve } = require ( 'path' ) ;
5
5
const { quote } = require ( 'shell-quote' ) ;
6
6
7
7
// Terminate early if this script is not invoked with the required arguments.
@@ -186,29 +186,96 @@ try {
186
186
cdsCommand = 'npx -y --package @sap/cds-dk cds' ;
187
187
}
188
188
189
+ /**
190
+ * Recursively renames all .json files to .cds.json in the given directory and
191
+ * its subdirectories, except for those that already have .cds.json extension.
192
+ *
193
+ * @param {string } dirPath - The directory path to start recursion from
194
+ */
195
+ function recursivelyRenameJsonFiles ( dirPath ) {
196
+ // Make sure the directory exists
197
+ if ( ! existsSync ( dirPath ) || ! statSync ( dirPath ) . isDirectory ( ) ) {
198
+ console . log ( `Directory not found or not a directory: ${ dirPath } ` ) ;
199
+ return ;
200
+ }
201
+ console . log ( `Processing JSON files in output directory: ${ dirPath } ` ) ;
202
+ // Get all entries in the directory
203
+ const entries = readdirSync ( dirPath , { withFileTypes : true } ) ;
204
+ for ( const entry of entries ) {
205
+ const fullPath = join ( dirPath , entry . name ) ;
206
+ if ( entry . isDirectory ( ) ) {
207
+ // Recursively process subdirectories
208
+ recursivelyRenameJsonFiles ( fullPath ) ;
209
+ } else if (
210
+ entry . isFile ( ) &&
211
+ entry . name . endsWith ( '.json' ) &&
212
+ ! entry . name . endsWith ( '.cds.json' )
213
+ ) {
214
+ // Rename .json files to .cds.json
215
+ const newPath = format ( { ...parse ( fullPath ) , base : '' , ext : '.cds.json' } ) ;
216
+ renameSync ( fullPath , newPath ) ;
217
+ console . log ( `Renamed CDS output file from ${ fullPath } to ${ newPath } ` ) ;
218
+ }
219
+ }
220
+ }
221
+
189
222
console . log ( 'Processing CDS files to JSON ...' ) ;
190
223
191
224
/**
192
225
* Run the cds compile command on each file in the response files list, outputting the
193
226
* compiled JSON to a file with the same name but with a .json extension appended.
194
227
*/
195
- responseFiles . forEach ( rawCdsFilePath => {
196
- const cdsFilePath = quote ( [ rawCdsFilePath ] ) ;
197
- const cdsJsonFilePath = `${ cdsFilePath } .json` ;
198
- console . log ( `Processing CDS file ${ cdsFilePath } to ${ cdsJsonFilePath } ...` ) ;
199
- const result = spawnSync (
200
- cdsCommand ,
201
- [
202
- 'compile' , cdsFilePath ,
203
- '-2' , 'json' ,
204
- '--locations' ,
205
- '--log-level' , 'warn'
206
- ] ,
207
- { shell : true , stdio : 'pipe' }
208
- ) ;
209
- if ( result . error || result . status !== 0 || ! result . stdout ) {
210
- const errorMessage = `Could not compile the file ${ cdsFilePath } .\nReported error(s):\n\`\`\`\n${ result . stderr . toString ( ) } \n\`\`\`` ;
211
- console . log ( errorMessage ) ;
228
+ for ( const rawCdsFilePath of responseFiles ) {
229
+ const cdsFilePath = resolve ( quote ( [ rawCdsFilePath ] ) ) ;
230
+ try {
231
+ if ( ! existsSync ( cdsFilePath ) ) {
232
+ throw new Error ( `Expected CDS file '${ cdsFilePath } ' does not exist.` ) ;
233
+ }
234
+ const cdsJsonOutPath = `${ cdsFilePath } .json` ;
235
+ console . log ( `Processing CDS file ${ cdsFilePath } to ${ cdsJsonOutPath } ...` ) ;
236
+ const result = spawnSync (
237
+ cdsCommand ,
238
+ [
239
+ 'compile' , cdsFilePath ,
240
+ '--to' , 'json' ,
241
+ '--dest' , cdsJsonOutPath ,
242
+ '--locations' ,
243
+ '--log-level' , 'warn'
244
+ ] ,
245
+ { cwd : sourceRoot , shell : true , stdio : 'pipe' }
246
+ ) ;
247
+ if ( result . error || result . status !== 0 ) {
248
+ throw new Error (
249
+ `Could not compile the file ${ cdsFilePath } .\nReported error(s):\n\`\`\`\n${ result . stderr . toString ( ) } \n\`\`\``
250
+ ) ;
251
+ }
252
+ /**
253
+ * The `cds compile` command chooses how it outputs the JSON. If it creates the
254
+ * output files in a directory (at cdsJsonOutPath), then it will create the
255
+ * directory when it runs and will choose the file names within that directory.
256
+ * If it creates the output as a single file (at cdsJsonOutPath), then there is
257
+ * nothing more to do as we create the output path by simple appending `.json` to
258
+ * the input file path/name, where the input path should already end with `.cds`
259
+ * (or else it shouldn't be in the response file).
260
+ *
261
+ * Therefore, if the output is a directory, we need to rename the output files
262
+ * to have a `.cds.json` extension, not just `.json`, so that the JS extractor
263
+ * recognizes them as CDS files to be indexed.
264
+ */
265
+ if ( ! existsSync ( cdsJsonOutPath ) || ( ! statSync ( cdsJsonOutPath ) . isFile ( ) && ! statSync ( cdsJsonOutPath ) . isDirectory ( ) ) ) {
266
+ throw new Error (
267
+ `CDS source file '${ cdsFilePath } ' was not compiled to JSON. This is likely because the file does not exist or is not a valid CDS file.`
268
+ ) ;
269
+ }
270
+ if ( statSync ( cdsJsonOutPath ) . isDirectory ( ) ) {
271
+ console . log ( `CDS compiler generated JSON to output directory: ${ cdsJsonOutPath } ` ) ;
272
+ // Recursively rename all .json files to have a .cds.json extension
273
+ recursivelyRenameJsonFiles ( cdsJsonOutPath ) ;
274
+ } else {
275
+ console . log ( `CDS compiler generated JSON to file: ${ cdsJsonOutPath } ` ) ;
276
+ }
277
+ } catch ( errorMessage ) {
278
+ console . error ( `ERROR: adding diagnostic for source file=${ cdsFilePath } : ${ errorMessage } ...` ) ;
212
279
try {
213
280
execFileSync (
214
281
codeqlExePath ,
@@ -228,12 +295,10 @@ responseFiles.forEach(rawCdsFilePath => {
228
295
) ;
229
296
console . log ( `Added error diagnostic for source file: ${ cdsFilePath } ` ) ;
230
297
} catch ( err ) {
231
- console . error ( `Failed to add error diagnostic for source file=${ cdsFilePath } : ${ err } ` ) ;
298
+ console . error ( `ERROR: Failed to add error diagnostic for source file=${ cdsFilePath } : ${ err } ` ) ;
232
299
}
233
300
}
234
- // Write the compiled JSON result to cdsJsonFilePath.
235
- writeFileSync ( cdsJsonFilePath , result . stdout ) ;
236
- } ) ;
301
+ }
237
302
238
303
let excludeFilters = '' ;
239
304
/**
@@ -274,9 +339,6 @@ console.log(`Set $LGTM_INDEX_FILTERS to:\n${process.env.LGTM_INDEX_FILTERS}`);
274
339
process . env . LGTM_INDEX_TYPESCRIPT = 'NONE' ;
275
340
// Configure to copy over the .cds files as well, by pretending they are JSON.
276
341
process . env . LGTM_INDEX_FILETYPES = '.cds:JSON' ;
277
- // Ignore the LGTM_INDEX_INCLUDE variable for this purpose as it may explicitly
278
- // refer to .js or .ts files.
279
- delete process . env . LGTM_INDEX_INCLUDE ;
280
342
281
343
console . log (
282
344
`Extracting the .cds.json files by running the 'javascript' extractor autobuild script:
0 commit comments