Skip to content

Commit 257fac2

Browse files
committed
Revert "Simplify CDS project compile command"
This reverts commit 119aa29.
1 parent 119aa29 commit 257fac2

File tree

3 files changed

+49
-490
lines changed

3 files changed

+49
-490
lines changed

extractors/cds/tools/src/cds/compiler/compile.ts

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,9 +131,20 @@ function compileProjectLevel(
131131
);
132132

133133
// For project-level compilation, compile the entire project together
134-
// Simply pass the project directory to cds compile and let it handle all subdirectories
134+
// This follows the CAP best practice of compiling db and srv directories together
135135
const projectAbsolutePath = join(sourceRoot, projectDir);
136136

137+
// Common directories in CAP projects that should be compiled together
138+
const capDirectories = ['db', 'srv', 'app'];
139+
const existingDirectories: string[] = [];
140+
141+
for (const dir of capDirectories) {
142+
const dirPath = join(projectAbsolutePath, dir);
143+
if (dirExists(dirPath)) {
144+
existingDirectories.push(dir);
145+
}
146+
}
147+
137148
// Check if there are any CDS files in the project at all before proceeding
138149
const allCdsFiles = globSync(join(projectAbsolutePath, '**/*.cds'), {
139150
nodir: true,
@@ -146,6 +157,24 @@ function compileProjectLevel(
146157
);
147158
}
148159

160+
if (existingDirectories.length === 0) {
161+
// If no standard directories, check if there are CDS files in the root
162+
const rootCdsFiles = globSync(join(projectAbsolutePath, '*.cds'));
163+
if (rootCdsFiles.length > 0) {
164+
existingDirectories.push('.');
165+
} else {
166+
// Find directories that contain CDS files
167+
const cdsFileParents = new Set(
168+
allCdsFiles.map((file: string) => {
169+
const relativePath = relative(projectAbsolutePath, file);
170+
const firstDir = relativePath.split('/')[0];
171+
return firstDir === relativePath ? '.' : firstDir;
172+
}),
173+
);
174+
existingDirectories.push(...Array.from(cdsFileParents));
175+
}
176+
}
177+
149178
// Generate output path for the compiled model - relative to sourceRoot for consistency
150179
const relativeOutputPath = join(projectDir, 'model.cds.json');
151180
const projectJsonOutPath = join(sourceRoot, relativeOutputPath);
@@ -156,10 +185,14 @@ function compileProjectLevel(
156185
cwd: sourceRoot, // Use sourceRoot as working directory for consistency
157186
};
158187

159-
// Simply compile the entire project directory - let cds compile handle all subdirectories
188+
// Convert directories to be relative to sourceRoot (include project prefix)
189+
const projectRelativeDirectories = existingDirectories.map(dir =>
190+
dir === '.' ? projectDir : join(projectDir, dir),
191+
);
192+
160193
const compileArgs = [
161194
'compile',
162-
projectDir, // Just pass the project directory, cds will find all relevant files
195+
...projectRelativeDirectories, // Use paths relative to sourceRoot
163196
'--to',
164197
'json',
165198
'--dest',
@@ -169,7 +202,7 @@ function compileProjectLevel(
169202
'warn',
170203
];
171204

172-
cdsExtractorLog('info', `Compiling CAP project directory: ${projectDir}`);
205+
cdsExtractorLog('info', `Compiling CAP project directories: ${existingDirectories.join(', ')}`);
173206
cdsExtractorLog(
174207
'info',
175208
`Executing CDS command in directory ${projectAbsolutePath}: command='${cdsCommand}' args='${JSON.stringify(compileArgs)}'`,

extractors/cds/tools/test/src/cds/compiler/compile.test.ts

Lines changed: 12 additions & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,7 @@ describe('compile .cds to .cds.json', () => {
421421
);
422422
});
423423

424-
it('should use sourceRoot as cwd for project-level compilation with simplified approach', () => {
424+
it('should use sourceRoot as cwd for project-level compilation', () => {
425425
// Setup
426426
const sourceRoot = '/source/root';
427427
const projectDir = 'test-project';
@@ -434,6 +434,9 @@ describe('compile .cds to .cds.json', () => {
434434
if (pattern.includes('**/*.cds')) {
435435
return ['test-project/srv/service.cds', 'test-project/db/schema.cds'];
436436
}
437+
if (pattern.includes('*.cds')) {
438+
return [];
439+
}
437440
return [];
438441
});
439442

@@ -447,79 +450,12 @@ describe('compile .cds to .cds.json', () => {
447450
};
448451
projectMap.set(projectDir, projectInfo);
449452

450-
// Mock successful spawn process
451-
(childProcess.spawnSync as jest.Mock).mockReturnValue({
452-
status: 0,
453-
stdout: Buffer.from('Compilation successful'),
454-
stderr: Buffer.from(''),
455-
});
456-
457-
// Execute
458-
const result = compileCdsToJson(
459-
'test.cds',
460-
sourceRoot,
461-
'cds',
462-
undefined,
463-
projectMap,
464-
projectDir,
465-
);
466-
467-
// Verify
468-
expect(result.success).toBe(true);
469-
expect(result.compiledAsProject).toBe(true);
470-
471-
// CRITICAL: Verify that project-level compilation uses sourceRoot as cwd with simplified approach
472-
expect(childProcess.spawnSync).toHaveBeenCalledWith(
473-
'cds',
474-
expect.arrayContaining(['compile', 'test-project']), // Just the project directory
475-
expect.objectContaining({
476-
cwd: sourceRoot, // CRITICAL: Must be sourceRoot, not projectAbsolutePath
477-
}),
478-
);
479-
480-
// Ensure no specific subdirectories are passed with simplified approach
481-
const actualCall = (childProcess.spawnSync as jest.Mock).mock.calls[0];
482-
const actualArgs = actualCall[1];
483-
expect(actualArgs).not.toContain('test-project/db');
484-
expect(actualArgs).not.toContain('test-project/srv');
485-
expect(actualArgs).toContain('test-project'); // Just the base project directory
486-
});
487-
488-
it('should use simplified project-level compilation with entire directory', () => {
489-
// Setup
490-
const sourceRoot = '/source/root';
491-
const projectDir = 'bookshop-project';
492-
493-
// Set up the path.relative mock
494-
(path.relative as jest.Mock).mockImplementation(() => 'bookshop-project/index.cds');
495-
496-
// Mock globSync to return CDS files including root-level index.cds
497-
(globSync as jest.Mock).mockImplementation((pattern: string) => {
498-
if (pattern.includes('**/*.cds')) {
499-
// Return all CDS files in the project
500-
return [
501-
'bookshop-project/index.cds',
502-
'bookshop-project/srv/cat-service.cds',
503-
'bookshop-project/db/schema.cds',
504-
];
505-
}
506-
return [];
453+
// Mock filesystem checks
454+
(filesystem.dirExists as jest.Mock).mockImplementation(path => {
455+
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
456+
return path.includes('/db') || path.includes('/srv');
507457
});
508458

509-
// Create project dependency map with project-level compilation marker
510-
const projectMap = new Map();
511-
const projectInfo = {
512-
projectDir,
513-
cdsFiles: [
514-
'bookshop-project/index.cds',
515-
'bookshop-project/srv/cat-service.cds',
516-
'bookshop-project/db/schema.cds',
517-
],
518-
cdsFilesToCompile: ['__PROJECT_LEVEL_COMPILATION__'],
519-
imports: new Map(),
520-
};
521-
projectMap.set(projectDir, projectInfo);
522-
523459
// Mock successful spawn process
524460
(childProcess.spawnSync as jest.Mock).mockReturnValue({
525461
status: 0,
@@ -529,7 +465,7 @@ describe('compile .cds to .cds.json', () => {
529465

530466
// Execute
531467
const result = compileCdsToJson(
532-
'index.cds',
468+
'test.cds',
533469
sourceRoot,
534470
'cds',
535471
undefined,
@@ -541,100 +477,14 @@ describe('compile .cds to .cds.json', () => {
541477
expect(result.success).toBe(true);
542478
expect(result.compiledAsProject).toBe(true);
543479

544-
// With simplified approach: just pass the project directory, let cds compile handle everything
480+
// CRITICAL: Verify that project-level compilation uses sourceRoot as cwd
545481
expect(childProcess.spawnSync).toHaveBeenCalledWith(
546482
'cds',
547-
expect.arrayContaining([
548-
'compile',
549-
'bookshop-project', // Only the project directory is needed
550-
]),
483+
expect.arrayContaining(['compile', 'test-project/db', 'test-project/srv']),
551484
expect.objectContaining({
552-
cwd: sourceRoot,
485+
cwd: sourceRoot, // CRITICAL: Must be sourceRoot, not projectAbsolutePath
553486
}),
554487
);
555-
556-
// Ensure no specific subdirectories are passed - cds compile handles them automatically
557-
const actualCall = (childProcess.spawnSync as jest.Mock).mock.calls[0];
558-
const actualArgs = actualCall[1];
559-
expect(actualArgs).not.toContain('bookshop-project/db');
560-
expect(actualArgs).not.toContain('bookshop-project/srv');
561-
expect(actualArgs).toContain('bookshop-project'); // Just the base project directory
562-
});
563-
564-
it('should compile entire project directory with simplified approach', () => {
565-
// This test verifies the simplified approach: instead of determining specific subdirectories,
566-
// we just pass the project directory to cds compile and let it handle everything.
567-
568-
// Setup
569-
const sourceRoot = '/source/root';
570-
const projectDir = 'bookshop-project';
571-
572-
// Set up the path.relative mock
573-
(path.relative as jest.Mock).mockImplementation(() => 'bookshop-project/index.cds');
574-
575-
// Mock globSync to return CDS files including root-level index.cds
576-
(globSync as jest.Mock).mockImplementation((pattern: string) => {
577-
if (pattern.includes('**/*.cds')) {
578-
// Return all CDS files in the project
579-
return [
580-
'bookshop-project/index.cds',
581-
'bookshop-project/srv/cat-service.cds',
582-
'bookshop-project/db/schema.cds',
583-
];
584-
}
585-
return [];
586-
});
587-
588-
// Create project dependency map with project-level compilation marker
589-
const projectMap = new Map();
590-
const projectInfo = {
591-
projectDir,
592-
cdsFiles: [
593-
'bookshop-project/index.cds',
594-
'bookshop-project/srv/cat-service.cds',
595-
'bookshop-project/db/schema.cds',
596-
],
597-
cdsFilesToCompile: ['__PROJECT_LEVEL_COMPILATION__'],
598-
imports: new Map(),
599-
};
600-
projectMap.set(projectDir, projectInfo);
601-
602-
// Mock successful spawn process
603-
(childProcess.spawnSync as jest.Mock).mockReturnValue({
604-
status: 0,
605-
stdout: Buffer.from('Compilation successful'),
606-
stderr: Buffer.from(''),
607-
});
608-
609-
// Execute
610-
const result = compileCdsToJson(
611-
'index.cds',
612-
sourceRoot,
613-
'cds',
614-
undefined,
615-
projectMap,
616-
projectDir,
617-
);
618-
619-
// Verify
620-
expect(result.success).toBe(true);
621-
expect(result.compiledAsProject).toBe(true);
622-
623-
// With the simplified approach, we should just pass the project directory
624-
// and let cds compile handle all subdirectories automatically
625-
const actualCall = (childProcess.spawnSync as jest.Mock).mock.calls[0];
626-
const actualArgs = actualCall[1]; // Second argument is the args array
627-
628-
// The compile command should include only the project directory
629-
expect(actualArgs).toContain('bookshop-project');
630-
631-
// Verify the simplified command structure
632-
const compileIndex = actualArgs.indexOf('compile');
633-
const destIndex = actualArgs.indexOf('--to');
634-
const directoryArgs = actualArgs.slice(compileIndex + 1, destIndex);
635-
636-
// Should only contain the project directory - no need to specify subdirectories
637-
expect(directoryArgs).toEqual(['bookshop-project']);
638488
});
639489
});
640490
});

0 commit comments

Comments
 (0)