11import { execFileSync , spawnSync , SpawnSyncOptions } from 'child_process' ;
2- import { resolve , join , delimiter } from 'path' ;
2+ import { resolve , join , delimiter , relative } from 'path' ;
33
44import { CdsCompilationResult } from './types' ;
55import { fileExists , dirExists , recursivelyRenameJsonFiles } from '../../filesystem' ;
@@ -87,13 +87,24 @@ export function getCdsVersion(cdsCommand: string, cacheDir?: string): string | u
8787 * @param sourceRoot The source root directory
8888 * @param cdsCommand The CDS command to use
8989 * @param cacheDir Optional path to a directory containing installed dependencies
90+ * @param projectMap Optional map of project directories to project objects with dependency information
91+ * @param projectDir Optional project directory this CDS file belongs to
9092 * @returns Result of the compilation
9193 */
9294export function compileCdsToJson (
9395 cdsFilePath : string ,
9496 sourceRoot : string ,
9597 cdsCommand : string ,
9698 cacheDir ?: string ,
99+ projectMap ?: Map <
100+ string ,
101+ {
102+ projectDir : string ;
103+ cdsFiles : string [ ] ;
104+ imports ?: Map < string , Array < { resolvedPath ?: string } > > ;
105+ }
106+ > ,
107+ projectDir ?: string ,
97108) : CdsCompilationResult {
98109 try {
99110 const resolvedCdsFilePath = resolve ( cdsFilePath ) ;
@@ -106,7 +117,6 @@ export function compileCdsToJson(
106117 // Get and log the CDS version
107118 const cdsVersion = getCdsVersion ( cdsCommand , cacheDir ) ;
108119 const versionInfo = cdsVersion ? `with CDS v${ cdsVersion } ` : '' ;
109- console . log ( `Processing CDS file ${ resolvedCdsFilePath } ${ versionInfo } ...` ) ;
110120
111121 // Prepare spawn options
112122 const spawnOptions : SpawnSyncOptions = {
@@ -128,25 +138,93 @@ export function compileCdsToJson(
128138 // Add NPM configuration to ensure dependencies are resolved from the cache directory
129139 npm_config_prefix : cacheDir ,
130140 } ;
141+ }
142+
143+ // Determine if we should compile this file directly or as part of a project
144+ // Check if the projectMap and projectDir are provided
145+ const isProjectAware = projectMap && projectDir && projectMap . get ( projectDir ) ;
146+ let isRootCdsFile = false ;
147+ let projectBasedCompilation = false ;
148+
149+ if ( isProjectAware ) {
150+ const project = projectMap . get ( projectDir ) ;
151+ const relativePath = relative ( sourceRoot , resolvedCdsFilePath ) ;
152+
153+ // Check if this is a root CDS file (not imported by other files)
154+ if ( project ?. cdsFiles ) {
155+ // Create a map to track imported files in the project
156+ const importedFiles = new Map < string , boolean > ( ) ;
131157
132- console . log ( `Using cached dependencies from: ${ cacheDir } ` ) ;
158+ // First pass: collect all imported files in the project
159+ for ( const file of project . cdsFiles ) {
160+ try {
161+ const absoluteFilePath = join ( sourceRoot , file ) ;
162+ if ( fileExists ( absoluteFilePath ) ) {
163+ // Get imports for this file
164+ const imports = project . imports ?. get ( file ) ?? [ ] ;
165+
166+ // Mark imported files
167+ for ( const importInfo of imports ) {
168+ if ( importInfo . resolvedPath ) {
169+ importedFiles . set ( importInfo . resolvedPath , true ) ;
170+ }
171+ }
172+ }
173+ } catch ( error ) {
174+ console . warn ( `Warning: Error processing imports for ${ file } : ${ String ( error ) } ` ) ;
175+ }
176+ }
177+
178+ // Check if current file is not imported by any other file in the project
179+ isRootCdsFile = ! importedFiles . has ( relativePath ) ;
180+
181+ // If the file is a root CDS file, we'll use a project-based compilation approach
182+ if ( isRootCdsFile ) {
183+ projectBasedCompilation = true ;
184+ console . log (
185+ `${ resolvedCdsFilePath } identified as a root CDS file - using project-aware compilation ${ versionInfo } ...` ,
186+ ) ;
187+ } else {
188+ console . log (
189+ `${ resolvedCdsFilePath } is imported by other files - will be compiled as part of a project ${ versionInfo } ...` ,
190+ ) ;
191+ }
192+ }
193+ } else {
194+ // Fallback to individual file compilation if project information is not available
195+ console . log ( `Processing individual CDS file ${ resolvedCdsFilePath } ${ versionInfo } ...` ) ;
196+ }
197+
198+ // If it's not a root file and project-based compilation is enabled,
199+ // return success without additional processing since it will be compiled as part of its root file
200+ if ( isProjectAware && ! isRootCdsFile ) {
201+ return {
202+ success : true ,
203+ outputPath : cdsJsonOutPath ,
204+ compiledAsProject : true ,
205+ message : 'File was compiled as part of a project-based compilation' ,
206+ } ;
133207 }
134208
135- const result = spawnSync (
136- cdsCommand ,
137- [
138- 'compile' ,
139- resolvedCdsFilePath ,
140- '--to' ,
141- 'json' ,
142- '--dest' ,
143- cdsJsonOutPath ,
144- '--locations' ,
145- '--log-level' ,
146- 'warn' ,
147- ] ,
148- spawnOptions ,
149- ) ;
209+ // Compile the file
210+ const compileArgs = [
211+ 'compile' ,
212+ resolvedCdsFilePath ,
213+ '--to' ,
214+ 'json' ,
215+ '--dest' ,
216+ cdsJsonOutPath ,
217+ '--locations' ,
218+ '--log-level' ,
219+ 'warn' ,
220+ ] ;
221+
222+ // For root CDS files in project-aware mode, add --parse flag to ensure complete model
223+ if ( projectBasedCompilation ) {
224+ compileArgs . push ( '--parse' ) ;
225+ }
226+
227+ const result = spawnSync ( cdsCommand , compileArgs , spawnOptions ) ;
150228
151229 if ( result . error ) {
152230 throw new Error ( `Error executing CDS compiler: ${ result . error . message } ` ) ;
@@ -175,7 +253,11 @@ export function compileCdsToJson(
175253 console . log ( `CDS compiler generated JSON to file: ${ cdsJsonOutPath } ` ) ;
176254 }
177255
178- return { success : true , outputPath : cdsJsonOutPath } ;
256+ return {
257+ success : true ,
258+ outputPath : cdsJsonOutPath ,
259+ compiledAsProject : projectBasedCompilation ,
260+ } ;
179261 } catch ( error ) {
180262 return { success : false , message : String ( error ) } ;
181263 }
0 commit comments