From 2fddff6cfa403013811f29ca318586d41d562b9a Mon Sep 17 00:00:00 2001 From: Mihai Herda Date: Tue, 2 Jun 2026 16:00:00 +0200 Subject: [PATCH 1/3] Emit one diagnostic per failed compilation, not per source file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When CDS compilation fails for a project, the extractor previously called `codeql database add-diagnostic` once for every source file in the project's failed compilation task. Because compilation is project-level (one task per project, with `task.sourceFiles` listing every CDS file), a project with hundreds of `.cds` files paid hundreds of `execFileSync(codeql, ...)` round trips at the end of a failed run — taking 30–40 minutes for ~1000-file projects. Emit a single diagnostic per failed task instead, attached to the project's `package.json` when available (or the project directory otherwise), and mention the affected file count in the message body so that information is preserved. The existing `cds/compilation-failure` source-id and "Failure to compile one or more SAP CAP CDS files" source-name already read as project-level, so no schema change is needed. Tests in `retry.test.ts` are updated for the new call shape and two new cases cover (a) a 250-file project emitting exactly one diagnostic and (b) projects without `package.json` falling back to the project directory. --- .../cds/tools/src/cds/compiler/retry.ts | 31 ++++++-- .../tools/test/src/cds/compiler/retry.test.ts | 79 +++++++++++++++++-- 2 files changed, 97 insertions(+), 13 deletions(-) diff --git a/extractors/cds/tools/src/cds/compiler/retry.ts b/extractors/cds/tools/src/cds/compiler/retry.ts index 27aa6b03f..ff60c3384 100644 --- a/extractors/cds/tools/src/cds/compiler/retry.ts +++ b/extractors/cds/tools/src/cds/compiler/retry.ts @@ -1,5 +1,7 @@ /** Main retry orchestration logic for CDS compilation failures. */ +import { join } from 'path'; + import { compileCdsToJson } from './compile'; import type { CompilationAttempt, @@ -16,6 +18,15 @@ import type { CdsDependencyGraph, CdsProject } from '../parser'; /** * Add diagnostics only for tasks with `status: failed` in the {@link CdsDependencyGraph}. + * + * Compilation is project-level: a single failed task represents the whole project's + * compilation failure, even though the task's `sourceFiles` may list every CDS file + * in the project. To avoid spawning the CodeQL CLI once per source file (which can + * take tens of minutes for projects with hundreds of `.cds` files), we emit a single + * diagnostic per failed task, attached to the project's `package.json` when available + * (or the project directory otherwise), and mention the affected file count in the + * message body so that information is preserved. + * * @param dependencyGraph The dependency graph to use as the source of truth for task status * @param codeqlExePath Path to CodeQL executable used to add a diagnostic notification * @param sourceRoot Source root directory to use for making file paths relative @@ -35,14 +46,18 @@ function addCompilationDiagnosticsForFailedTasks( const shouldAddDiagnostic = task.retryInfo?.hasBeenRetried ?? !task.retryInfo; if (shouldAddDiagnostic) { - for (const sourceFile of task.sourceFiles) { - addCompilationDiagnostic( - sourceFile, - task.errorSummary ?? 'Compilation failed', - codeqlExePath, - sourceRoot, - ); - } + // Attach the diagnostic to the project's package.json when available, + // otherwise fall back to the project directory itself. + const diagnosticPath = project.packageJson + ? join(project.projectDir, 'package.json') + : project.projectDir; + + const fileCount = task.sourceFiles.length; + const fileWord = fileCount === 1 ? 'file' : 'files'; + const baseMessage = task.errorSummary ?? 'Compilation failed'; + const messageWithCount = `${baseMessage}\n\n${fileCount} CDS ${fileWord} in this project ${fileCount === 1 ? 'was' : 'were'} not extracted.`; + + addCompilationDiagnostic(diagnosticPath, messageWithCount, codeqlExePath, sourceRoot); } } } diff --git a/extractors/cds/tools/test/src/cds/compiler/retry.test.ts b/extractors/cds/tools/test/src/cds/compiler/retry.test.ts index f0ec1692b..8c609cc9f 100644 --- a/extractors/cds/tools/test/src/cds/compiler/retry.test.ts +++ b/extractors/cds/tools/test/src/cds/compiler/retry.test.ts @@ -1,5 +1,7 @@ /** Tests for retry orchestration logic */ +import { join } from 'path'; + import * as compile from '../../../../src/cds/compiler/compile'; import { orchestrateRetryAttempts } from '../../../../src/cds/compiler/retry'; import type { CompilationTask } from '../../../../src/cds/compiler/types'; @@ -453,10 +455,12 @@ describe('retry.ts', () => { // Execute orchestrateRetryAttempts(mockDependencyGraph, codeqlExePath); - // Verify diagnostics are added for failed tasks + // Verify a single project-level diagnostic is added (attached to the project's + // package.json) rather than one per source file. + expect(mockDiagnostics.addCompilationDiagnostic).toHaveBeenCalledTimes(1); expect(mockDiagnostics.addCompilationDiagnostic).toHaveBeenCalledWith( - '/test/project/db/schema.cds', - expect.any(String), + join('test-project', 'package.json'), + expect.stringContaining('1 CDS file in this project was not extracted.'), codeqlExePath, '/test', ); @@ -482,9 +486,74 @@ describe('retry.ts', () => { orchestrateRetryAttempts(mockDependencyGraph, codeqlExePath); - // Verify diagnostics are added for tasks that were never retried (retryInfo is undefined) + // Verify a single project-level diagnostic is added for tasks that were never + // retried (retryInfo is undefined), rather than one per source file. + expect(mockDiagnostics.addCompilationDiagnostic).toHaveBeenCalledTimes(1); + expect(mockDiagnostics.addCompilationDiagnostic).toHaveBeenCalledWith( + join('test-project', 'package.json'), + expect.stringContaining('1 CDS file in this project was not extracted.'), + codeqlExePath, + '/test', + ); + }); + + it('should emit a single diagnostic per failed task regardless of source file count', () => { + // Setup: A single failed task with many source files (simulating a large project). + const manyFiles = Array.from({ length: 250 }, (_, i) => `/test/project/db/file${i}.cds`); + const failedTask: CompilationTask = { + ...mockFailedTask, + sourceFiles: manyFiles, + retryInfo: { hasBeenRetried: true, retryReason: 'Test retry' }, + status: 'failed', + }; + mockProject.compilationTasks = [failedTask]; + mockProject.cdsFiles = manyFiles; + + const tasksRequiringRetry = new Map([['test-project', [failedTask]]]); + mockValidator.identifyTasksRequiringRetry.mockReturnValue(tasksRequiringRetry); + mockPackageManager.needsFullDependencyInstallation.mockReturnValue(false); + + mockCompile.compileCdsToJson.mockReturnValue({ + success: false, + message: 'Compilation failed', + durationMs: 500, + }); + + orchestrateRetryAttempts(mockDependencyGraph, codeqlExePath); + + // One diagnostic per failed task — not one per source file. + expect(mockDiagnostics.addCompilationDiagnostic).toHaveBeenCalledTimes(1); + expect(mockDiagnostics.addCompilationDiagnostic).toHaveBeenCalledWith( + join('test-project', 'package.json'), + expect.stringContaining('250 CDS files in this project were not extracted.'), + codeqlExePath, + '/test', + ); + }); + + it('should attach the diagnostic to the project directory when no package.json exists', () => { + // Setup: A failed task on a project that has no package.json. + const failedTask = { ...mockFailedTask }; + failedTask.retryInfo = { hasBeenRetried: true, retryReason: 'Test retry' }; + failedTask.status = 'failed'; + mockProject.compilationTasks = [failedTask]; + mockProject.packageJson = undefined; + + const tasksRequiringRetry = new Map([['test-project', [failedTask]]]); + mockValidator.identifyTasksRequiringRetry.mockReturnValue(tasksRequiringRetry); + mockPackageManager.needsFullDependencyInstallation.mockReturnValue(false); + + mockCompile.compileCdsToJson.mockReturnValue({ + success: false, + message: 'Compilation failed', + durationMs: 500, + }); + + orchestrateRetryAttempts(mockDependencyGraph, codeqlExePath); + + expect(mockDiagnostics.addCompilationDiagnostic).toHaveBeenCalledTimes(1); expect(mockDiagnostics.addCompilationDiagnostic).toHaveBeenCalledWith( - '/test/project/db/schema.cds', + 'test-project', expect.any(String), codeqlExePath, '/test', From a73b61fd6b7d58d93a98c3852a7d8898a64f851e Mon Sep 17 00:00:00 2001 From: Mihai Herda Date: Tue, 2 Jun 2026 16:05:46 +0200 Subject: [PATCH 2/3] Lower CDS compilation diagnostic severity from error to warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A failed CDS compilation does not fail the overall scan — the JavaScript extractor still runs over the source root and other-language analyses proceed normally. Surfacing as a warning matches that reality and avoids flagging the run as having errors when no security-relevant findings were missed. --- extractors/cds/tools/src/diagnostics.ts | 4 ++-- extractors/cds/tools/test/src/diagnostics.test.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/extractors/cds/tools/src/diagnostics.ts b/extractors/cds/tools/src/diagnostics.ts index 0d5ae3ae2..72da98007 100644 --- a/extractors/cds/tools/src/diagnostics.ts +++ b/extractors/cds/tools/src/diagnostics.ts @@ -148,7 +148,7 @@ export function addCdsIndexerDiagnostic( } /** - * Add a diagnostic error to the CodeQL database for a failed CDS compilation + * Add a diagnostic warning to the CodeQL database for a failed CDS compilation * @param cdsFilePath Path to the CDS file that failed to compile * @param errorMessage The error message from the compilation * @param codeqlExePath Path to the CodeQL executable @@ -167,7 +167,7 @@ export function addCompilationDiagnostic( codeqlExePath, 'cds/compilation-failure', 'Failure to compile one or more SAP CAP CDS files', - DiagnosticSeverity.Error, + DiagnosticSeverity.Warning, 'source file', sourceRoot, ); diff --git a/extractors/cds/tools/test/src/diagnostics.test.ts b/extractors/cds/tools/test/src/diagnostics.test.ts index 888a18cce..77f7bb94a 100644 --- a/extractors/cds/tools/test/src/diagnostics.test.ts +++ b/extractors/cds/tools/test/src/diagnostics.test.ts @@ -344,7 +344,7 @@ describe('diagnostics', () => { '--ready-for-status-page', '--source-id=cds/compilation-failure', '--source-name=Failure to compile one or more SAP CAP CDS files', - '--severity=error', + '--severity=warning', `--markdown-message=${errorMessage}`, `--file-path=${cdsFilePath}`, '--', @@ -375,7 +375,7 @@ describe('diagnostics', () => { expect(result).toBe(false); expect(console.error).toHaveBeenCalledWith( expect.stringContaining( - `ERROR: Failed to add error diagnostic for source file=${cdsFilePath}`, + `ERROR: Failed to add warning diagnostic for source file=${cdsFilePath}`, ), ); From a6e15fd5d0bd6ce8fc75fd62c54b263052415357 Mon Sep 17 00:00:00 2001 From: Mihai Herda Date: Tue, 2 Jun 2026 16:08:19 +0200 Subject: [PATCH 3/3] Rebuild dist bundle --- .../cds/tools/dist/cds-extractor.bundle.js | 141 +++++++++--------- .../tools/dist/cds-extractor.bundle.js.map | 8 +- 2 files changed, 76 insertions(+), 73 deletions(-) diff --git a/extractors/cds/tools/dist/cds-extractor.bundle.js b/extractors/cds/tools/dist/cds-extractor.bundle.js index 2d7c9e62d..47e6b3584 100644 --- a/extractors/cds/tools/dist/cds-extractor.bundle.js +++ b/extractors/cds/tools/dist/cds-extractor.bundle.js @@ -24,7 +24,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge )); // cds-extractor.ts -var import_path16 = require("path"); +var import_path17 = require("path"); // node_modules/glob/dist/esm/index.min.js var import_node_url = require("node:url"); @@ -8487,6 +8487,9 @@ function createSpawnOptions(projectBaseDir, cdsCommand, cacheDir) { return spawnOptions; } +// src/cds/compiler/retry.ts +var import_path11 = require("path"); + // src/cds/compiler/validator.ts var import_fs6 = require("fs"); var import_path7 = require("path"); @@ -8690,7 +8693,7 @@ function addCompilationDiagnostic(cdsFilePath, errorMessage, codeqlExePath2, sou codeqlExePath2, "cds/compilation-failure", "Failure to compile one or more SAP CAP CDS files", - "error" /* Error */, + "warning" /* Warning */, "source file", sourceRoot2 ); @@ -9341,14 +9344,14 @@ function addCompilationDiagnosticsForFailedTasks(dependencyGraph2, codeqlExePath if (task.status === "failed") { const shouldAddDiagnostic = task.retryInfo?.hasBeenRetried ?? !task.retryInfo; if (shouldAddDiagnostic) { - for (const sourceFile of task.sourceFiles) { - addCompilationDiagnostic( - sourceFile, - task.errorSummary ?? "Compilation failed", - codeqlExePath2, - sourceRoot2 - ); - } + const diagnosticPath = project.packageJson ? (0, import_path11.join)(project.projectDir, "package.json") : project.projectDir; + const fileCount = task.sourceFiles.length; + const fileWord = fileCount === 1 ? "file" : "files"; + const baseMessage = task.errorSummary ?? "Compilation failed"; + const messageWithCount = `${baseMessage} + +${fileCount} CDS ${fileWord} in this project ${fileCount === 1 ? "was" : "were"} not extracted.`; + addCompilationDiagnostic(diagnosticPath, messageWithCount, codeqlExePath2, sourceRoot2); } } } @@ -9840,11 +9843,11 @@ function planCompilationTasks(dependencyGraph2, projectCacheDirMap2) { } // src/cds/compiler/project.ts -var import_path11 = require("path"); +var import_path12 = require("path"); // src/cds/indexer.ts var import_child_process9 = require("child_process"); -var import_path12 = require("path"); +var import_path13 = require("path"); var CDS_INDEXER_TIMEOUT_MS = 6e5; var CDS_INDEXER_PACKAGE = "@sap/cds-indexer"; function projectUsesCdsIndexer(project) { @@ -9856,7 +9859,7 @@ function projectUsesCdsIndexer(project) { return inDeps || inDevDeps; } function runCdsIndexer(project, sourceRoot2, cacheDir) { - const projectAbsPath = (0, import_path12.join)(sourceRoot2, project.projectDir); + const projectAbsPath = (0, import_path13.join)(sourceRoot2, project.projectDir); const startTime = Date.now(); const result = { success: false, @@ -9867,12 +9870,12 @@ function runCdsIndexer(project, sourceRoot2, cacheDir) { try { const nodePaths = []; if (cacheDir) { - nodePaths.push((0, import_path12.join)(cacheDir, "node_modules")); + nodePaths.push((0, import_path13.join)(cacheDir, "node_modules")); } - nodePaths.push((0, import_path12.join)(projectAbsPath, "node_modules")); + nodePaths.push((0, import_path13.join)(projectAbsPath, "node_modules")); const env = { ...process.env, - NODE_PATH: nodePaths.join(import_path12.delimiter) + NODE_PATH: nodePaths.join(import_path13.delimiter) }; cdsExtractorLog( "info", @@ -9965,11 +9968,11 @@ function orchestrateCdsIndexer(dependencyGraph2, sourceRoot2, projectCacheDirMap } // src/cds/parser/graph.ts -var import_path14 = require("path"); +var import_path15 = require("path"); // src/cds/parser/functions.ts var import_fs8 = require("fs"); -var import_path13 = require("path"); +var import_path14 = require("path"); function determineCdsFilesForProjectDir(sourceRootDir, projectDir) { if (!sourceRootDir || !projectDir) { throw new Error( @@ -9984,12 +9987,12 @@ function determineCdsFilesForProjectDir(sourceRootDir, projectDir) { ); } try { - const cdsFiles = Ui((0, import_path13.join)(projectDir, "**/*.cds"), { + const cdsFiles = Ui((0, import_path14.join)(projectDir, "**/*.cds"), { nodir: true, ignore: ["**/node_modules/**", "**/*.testproj/**"], windowsPathsNoEscape: true }); - const relativePaths = cdsFiles.map((file) => (0, import_path13.relative)(sourceRootDir, file)); + const relativePaths = cdsFiles.map((file) => (0, import_path14.relative)(sourceRootDir, file)); const pathsIgnorePatterns = getPathsIgnorePatterns(sourceRootDir); if (pathsIgnorePatterns.length > 0) { const filtered = filterIgnoredPaths(relativePaths, pathsIgnorePatterns); @@ -9997,7 +10000,7 @@ function determineCdsFilesForProjectDir(sourceRootDir, projectDir) { if (ignoredCount > 0) { cdsExtractorLog( "info", - `Filtered ${ignoredCount} CDS file(s) matching paths-ignore patterns in project ${(0, import_path13.relative)(sourceRootDir, projectDir) || "."}` + `Filtered ${ignoredCount} CDS file(s) matching paths-ignore patterns in project ${(0, import_path14.relative)(sourceRootDir, projectDir) || "."}` ); } return filtered; @@ -10013,22 +10016,22 @@ function determineCdsProjectsUnderSourceDir(sourceRootDir) { throw new Error(`Source root directory '${sourceRootDir}' does not exist.`); } const foundProjects = /* @__PURE__ */ new Set(); - const packageJsonFiles = Ui((0, import_path13.join)(sourceRootDir, "**/package.json"), { + const packageJsonFiles = Ui((0, import_path14.join)(sourceRootDir, "**/package.json"), { nodir: true, ignore: ["**/node_modules/**", "**/*.testproj/**"], windowsPathsNoEscape: true }); - const cdsFiles = Ui((0, import_path13.join)(sourceRootDir, "**/*.cds"), { + const cdsFiles = Ui((0, import_path14.join)(sourceRootDir, "**/*.cds"), { nodir: true, ignore: ["**/node_modules/**", "**/*.testproj/**"], windowsPathsNoEscape: true }); const candidateDirectories = /* @__PURE__ */ new Set(); for (const packageJsonFile of packageJsonFiles) { - candidateDirectories.add((0, import_path13.dirname)(packageJsonFile)); + candidateDirectories.add((0, import_path14.dirname)(packageJsonFile)); } for (const cdsFile of cdsFiles) { - const cdsDir = (0, import_path13.dirname)(cdsFile); + const cdsDir = (0, import_path14.dirname)(cdsFile); const projectRoot = findProjectRootFromCdsFile(cdsDir, sourceRootDir); if (projectRoot) { candidateDirectories.add(projectRoot); @@ -10038,14 +10041,14 @@ function determineCdsProjectsUnderSourceDir(sourceRootDir) { } for (const dir of candidateDirectories) { if (isLikelyCdsProject(dir)) { - const relativePath = (0, import_path13.relative)(sourceRootDir, dir); + const relativePath = (0, import_path14.relative)(sourceRootDir, dir); const projectDir = relativePath || "."; let shouldAdd = true; const existingProjects = Array.from(foundProjects); for (const existingProject of existingProjects) { - const existingAbsPath = (0, import_path13.join)(sourceRootDir, existingProject); - if (dir.startsWith(existingAbsPath + import_path13.sep)) { - const parentPackageJsonPath = (0, import_path13.join)(existingAbsPath, "package.json"); + const existingAbsPath = (0, import_path14.join)(sourceRootDir, existingProject); + if (dir.startsWith(existingAbsPath + import_path14.sep)) { + const parentPackageJsonPath = (0, import_path14.join)(existingAbsPath, "package.json"); const parentPackageJson = readPackageJsonFile(parentPackageJsonPath); const isParentMonorepo = parentPackageJson?.workspaces && Array.isArray(parentPackageJson.workspaces) && parentPackageJson.workspaces.length > 0; if (isParentMonorepo && (hasStandardCdsContent(existingAbsPath) || hasDirectCdsContent(existingAbsPath))) { @@ -10055,8 +10058,8 @@ function determineCdsProjectsUnderSourceDir(sourceRootDir) { } break; } - if (existingAbsPath.startsWith(dir + import_path13.sep)) { - const currentPackageJsonPath = (0, import_path13.join)(dir, "package.json"); + if (existingAbsPath.startsWith(dir + import_path14.sep)) { + const currentPackageJsonPath = (0, import_path14.join)(dir, "package.json"); const currentPackageJson = readPackageJsonFile(currentPackageJsonPath); const isCurrentMonorepo = currentPackageJson?.workspaces && Array.isArray(currentPackageJson.workspaces) && currentPackageJson.workspaces.length > 0; if (!(isCurrentMonorepo && isLikelyCdsProject(existingAbsPath))) { @@ -10097,32 +10100,32 @@ function findProjectRootFromCdsFile(cdsFileDir, sourceRootDir) { let currentDir = cdsFileDir; while (currentDir.startsWith(sourceRootDir)) { if (isLikelyCdsProject(currentDir)) { - const currentDirName = (0, import_path13.basename)(currentDir); + const currentDirName = (0, import_path14.basename)(currentDir); const isStandardSubdir = ["srv", "db", "app"].includes(currentDirName); if (isStandardSubdir) { - const parentDir3 = (0, import_path13.dirname)(currentDir); + const parentDir3 = (0, import_path14.dirname)(currentDir); if (parentDir3 !== currentDir && parentDir3.startsWith(sourceRootDir) && !parentDir3.includes("node_modules") && !parentDir3.includes(".testproj") && isLikelyCdsProject(parentDir3)) { return parentDir3; } } - const parentDir2 = (0, import_path13.dirname)(currentDir); + const parentDir2 = (0, import_path14.dirname)(currentDir); if (parentDir2 !== currentDir && parentDir2.startsWith(sourceRootDir) && !parentDir2.includes("node_modules") && !parentDir2.includes(".testproj")) { - const hasDbDir2 = (0, import_fs8.existsSync)((0, import_path13.join)(parentDir2, "db")) && (0, import_fs8.statSync)((0, import_path13.join)(parentDir2, "db")).isDirectory(); - const hasSrvDir2 = (0, import_fs8.existsSync)((0, import_path13.join)(parentDir2, "srv")) && (0, import_fs8.statSync)((0, import_path13.join)(parentDir2, "srv")).isDirectory(); - const hasAppDir2 = (0, import_fs8.existsSync)((0, import_path13.join)(parentDir2, "app")) && (0, import_fs8.statSync)((0, import_path13.join)(parentDir2, "app")).isDirectory(); + const hasDbDir2 = (0, import_fs8.existsSync)((0, import_path14.join)(parentDir2, "db")) && (0, import_fs8.statSync)((0, import_path14.join)(parentDir2, "db")).isDirectory(); + const hasSrvDir2 = (0, import_fs8.existsSync)((0, import_path14.join)(parentDir2, "srv")) && (0, import_fs8.statSync)((0, import_path14.join)(parentDir2, "srv")).isDirectory(); + const hasAppDir2 = (0, import_fs8.existsSync)((0, import_path14.join)(parentDir2, "app")) && (0, import_fs8.statSync)((0, import_path14.join)(parentDir2, "app")).isDirectory(); if (hasDbDir2 && hasSrvDir2 || hasSrvDir2 && hasAppDir2) { return parentDir2; } } return currentDir; } - const hasDbDir = (0, import_fs8.existsSync)((0, import_path13.join)(currentDir, "db")) && (0, import_fs8.statSync)((0, import_path13.join)(currentDir, "db")).isDirectory(); - const hasSrvDir = (0, import_fs8.existsSync)((0, import_path13.join)(currentDir, "srv")) && (0, import_fs8.statSync)((0, import_path13.join)(currentDir, "srv")).isDirectory(); - const hasAppDir = (0, import_fs8.existsSync)((0, import_path13.join)(currentDir, "app")) && (0, import_fs8.statSync)((0, import_path13.join)(currentDir, "app")).isDirectory(); + const hasDbDir = (0, import_fs8.existsSync)((0, import_path14.join)(currentDir, "db")) && (0, import_fs8.statSync)((0, import_path14.join)(currentDir, "db")).isDirectory(); + const hasSrvDir = (0, import_fs8.existsSync)((0, import_path14.join)(currentDir, "srv")) && (0, import_fs8.statSync)((0, import_path14.join)(currentDir, "srv")).isDirectory(); + const hasAppDir = (0, import_fs8.existsSync)((0, import_path14.join)(currentDir, "app")) && (0, import_fs8.statSync)((0, import_path14.join)(currentDir, "app")).isDirectory(); if (hasDbDir && hasSrvDir || hasSrvDir && hasAppDir) { return currentDir; } - const parentDir = (0, import_path13.dirname)(currentDir); + const parentDir = (0, import_path14.dirname)(currentDir); if (parentDir === currentDir) { break; } @@ -10143,7 +10146,7 @@ function isLikelyCdsProject(dir) { if (!hasCdsFiles) { return false; } - const packageJsonPath = (0, import_path13.join)(dir, "package.json"); + const packageJsonPath = (0, import_path14.join)(dir, "package.json"); const packageJson = readPackageJsonFile(packageJsonPath); if (packageJson?.workspaces && Array.isArray(packageJson.workspaces) && packageJson.workspaces.length > 0) { if (!hasCdsFiles) { @@ -10159,10 +10162,10 @@ function isLikelyCdsProject(dir) { } } function hasStandardCdsContent(dir) { - const standardLocations = [(0, import_path13.join)(dir, "db"), (0, import_path13.join)(dir, "srv"), (0, import_path13.join)(dir, "app")]; + const standardLocations = [(0, import_path14.join)(dir, "db"), (0, import_path14.join)(dir, "srv"), (0, import_path14.join)(dir, "app")]; for (const location of standardLocations) { if ((0, import_fs8.existsSync)(location) && (0, import_fs8.statSync)(location).isDirectory()) { - const cdsFiles = Ui((0, import_path13.join)(location, "**/*.cds"), { + const cdsFiles = Ui((0, import_path14.join)(location, "**/*.cds"), { nodir: true, windowsPathsNoEscape: true }); @@ -10174,7 +10177,7 @@ function hasStandardCdsContent(dir) { return false; } function hasDirectCdsContent(dir) { - const directCdsFiles = Ui((0, import_path13.join)(dir, "*.cds"), { windowsPathsNoEscape: true }); + const directCdsFiles = Ui((0, import_path14.join)(dir, "*.cds"), { windowsPathsNoEscape: true }); return directCdsFiles.length > 0; } function readPackageJsonFile(filePath) { @@ -10194,36 +10197,36 @@ function determineCdsFilesToCompile(sourceRootDir, project) { if (!project.cdsFiles || project.cdsFiles.length === 0) { return { compilationTargets: [], - expectedOutputFile: (0, import_path13.join)(project.projectDir, modelCdsJsonFile) + expectedOutputFile: (0, import_path14.join)(project.projectDir, modelCdsJsonFile) }; } - const absoluteProjectDir = (0, import_path13.join)(sourceRootDir, project.projectDir); + const absoluteProjectDir = (0, import_path14.join)(sourceRootDir, project.projectDir); const capDirectories = ["db", "srv", "app"]; - const existingCapDirs = capDirectories.filter((dir) => (0, import_fs8.existsSync)((0, import_path13.join)(absoluteProjectDir, dir))); + const existingCapDirs = capDirectories.filter((dir) => (0, import_fs8.existsSync)((0, import_path14.join)(absoluteProjectDir, dir))); if (existingCapDirs.length > 0) { return { compilationTargets: existingCapDirs, - expectedOutputFile: (0, import_path13.join)(project.projectDir, modelCdsJsonFile) + expectedOutputFile: (0, import_path14.join)(project.projectDir, modelCdsJsonFile) }; } - const rootCdsFiles = project.cdsFiles.filter((file) => (0, import_path13.dirname)((0, import_path13.join)(sourceRootDir, file)) === absoluteProjectDir).map((file) => (0, import_path13.basename)(file)); + const rootCdsFiles = project.cdsFiles.filter((file) => (0, import_path14.dirname)((0, import_path14.join)(sourceRootDir, file)) === absoluteProjectDir).map((file) => (0, import_path14.basename)(file)); if (rootCdsFiles.length > 0) { return { compilationTargets: rootCdsFiles, - expectedOutputFile: (0, import_path13.join)(project.projectDir, modelCdsJsonFile) + expectedOutputFile: (0, import_path14.join)(project.projectDir, modelCdsJsonFile) }; } const compilationTargets = project.cdsFiles.map( - (file) => (0, import_path13.relative)(absoluteProjectDir, (0, import_path13.join)(sourceRootDir, file)) + (file) => (0, import_path14.relative)(absoluteProjectDir, (0, import_path14.join)(sourceRootDir, file)) ); return { compilationTargets, - expectedOutputFile: (0, import_path13.join)(project.projectDir, modelCdsJsonFile) + expectedOutputFile: (0, import_path14.join)(project.projectDir, modelCdsJsonFile) }; } function hasPackageJsonWithCapDeps(dir) { try { - const packageJsonPath = (0, import_path13.join)(dir, "package.json"); + const packageJsonPath = (0, import_path14.join)(dir, "package.json"); const packageJson = readPackageJsonFile(packageJsonPath); if (packageJson) { const dependencies = { @@ -10254,7 +10257,7 @@ function buildBasicCdsProjectDependencyGraph(sourceRootDir) { cdsExtractorLog("info", `Skipping project '${projectDir}' \u2014 matches paths-ignore pattern`); continue; } - const absoluteProjectDir = (0, import_path14.join)(sourceRootDir, projectDir); + const absoluteProjectDir = (0, import_path15.join)(sourceRootDir, projectDir); const cdsFiles = determineCdsFilesForProjectDir(sourceRootDir, absoluteProjectDir); if (cdsFiles.length === 0) { cdsExtractorLog( @@ -10263,14 +10266,14 @@ function buildBasicCdsProjectDependencyGraph(sourceRootDir) { ); continue; } - const packageJsonPath = (0, import_path14.join)(absoluteProjectDir, "package.json"); + const packageJsonPath = (0, import_path15.join)(absoluteProjectDir, "package.json"); const packageJson = readPackageJsonFile(packageJsonPath); projectMap.set(projectDir, { projectDir, cdsFiles, compilationTargets: [], // Will be populated in the third pass - expectedOutputFile: (0, import_path14.join)(projectDir, modelCdsJsonFile), + expectedOutputFile: (0, import_path15.join)(projectDir, modelCdsJsonFile), packageJson, dependencies: [], imports: /* @__PURE__ */ new Map() @@ -10279,18 +10282,18 @@ function buildBasicCdsProjectDependencyGraph(sourceRootDir) { cdsExtractorLog("info", "Analyzing dependencies between CDS projects..."); for (const [projectDir, project] of projectMap.entries()) { for (const relativeFilePath of project.cdsFiles) { - const absoluteFilePath = (0, import_path14.join)(sourceRootDir, relativeFilePath); + const absoluteFilePath = (0, import_path15.join)(sourceRootDir, relativeFilePath); try { const imports = extractCdsImports(absoluteFilePath); const enrichedImports = []; for (const importInfo of imports) { const enrichedImport = { ...importInfo }; if (importInfo.isRelative) { - const importedFilePath = (0, import_path14.resolve)((0, import_path14.dirname)(absoluteFilePath), importInfo.path); + const importedFilePath = (0, import_path15.resolve)((0, import_path15.dirname)(absoluteFilePath), importInfo.path); const normalizedImportedPath = importedFilePath.endsWith(".cds") ? importedFilePath : `${importedFilePath}.cds`; try { - const relativeToDirPath = (0, import_path14.dirname)(relativeFilePath); - const resolvedPath = (0, import_path14.resolve)((0, import_path14.join)(sourceRootDir, relativeToDirPath), importInfo.path); + const relativeToDirPath = (0, import_path15.dirname)(relativeFilePath); + const resolvedPath = (0, import_path15.resolve)((0, import_path15.join)(sourceRootDir, relativeToDirPath), importInfo.path); const normalizedResolvedPath = resolvedPath.endsWith(".cds") ? resolvedPath : `${resolvedPath}.cds`; if (normalizedResolvedPath.startsWith(sourceRootDir)) { enrichedImport.resolvedPath = normalizedResolvedPath.substring(sourceRootDir.length).replace(/^[/\\]/, ""); @@ -10303,10 +10306,10 @@ function buildBasicCdsProjectDependencyGraph(sourceRootDir) { } for (const [otherProjectDir, otherProject] of projectMap.entries()) { if (otherProjectDir === projectDir) continue; - const otherProjectAbsoluteDir = (0, import_path14.join)(sourceRootDir, otherProjectDir); + const otherProjectAbsoluteDir = (0, import_path15.join)(sourceRootDir, otherProjectDir); const isInOtherProject = otherProject.cdsFiles.some((otherFile) => { - const otherAbsolutePath = (0, import_path14.join)(sourceRootDir, otherFile); - return otherAbsolutePath === normalizedImportedPath || normalizedImportedPath.startsWith(otherProjectAbsoluteDir + import_path14.sep); + const otherAbsolutePath = (0, import_path15.join)(sourceRootDir, otherFile); + return otherAbsolutePath === normalizedImportedPath || normalizedImportedPath.startsWith(otherProjectAbsoluteDir + import_path15.sep); }); if (isInOtherProject) { project.dependencies ??= []; @@ -10349,8 +10352,8 @@ function buildBasicCdsProjectDependencyGraph(sourceRootDir) { "warn", `Error determining files to compile for project ${project.projectDir}: ${String(error)}` ); - project.compilationTargets = project.cdsFiles.map((file) => (0, import_path14.basename)(file)); - project.expectedOutputFile = (0, import_path14.join)(project.projectDir, modelCdsJsonFile); + project.compilationTargets = project.cdsFiles.map((file) => (0, import_path15.basename)(file)); + project.expectedOutputFile = (0, import_path15.join)(project.projectDir, modelCdsJsonFile); } } return projectMap; @@ -10558,13 +10561,13 @@ function handleEarlyExit(sourceRoot2, autobuildScriptPath2, codeqlExePath2, skip } // src/utils.ts -var import_path15 = require("path"); +var import_path16 = require("path"); var USAGE_MESSAGE = ` Usage: node