Skip to content

Commit 337de12

Browse files
committed
fix: normalize CDS $location.file paths for Windows
The SAP CDS compiler on Windows produces $location.file values with backslashes (e.g. "srv\service1.cds"), causing CodeQL CAP library path matching to fail. Normalize these to OS-appropriate slashes at generation time in the CDS extractor, workflow scripts, and a new standalone normalizer script. - Add normalizeCdsJsonLocations/normalizeLocationPathsInFile to filesystem.ts with 12 unit tests - Call normalizeLocationPathsInFile after compilation in compile.ts - Add normalize-cds-json-paths.mjs standalone CLI for workflow use - Update cds-compilation-for-actions.cmd/.sh to call normalizer - Fix broken for /r loop in .cmd that skipped subdirectory CDS files - Update CDL.qll comments to document the normalization contract
1 parent 7f7d44d commit 337de12

File tree

10 files changed

+475
-67
lines changed

10 files changed

+475
-67
lines changed

extractors/cds/tools/dist/cds-extractor.bundle.js

Lines changed: 86 additions & 57 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

extractors/cds/tools/dist/cds-extractor.bundle.js.map

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#!/usr/bin/env node
2+
3+
/**
4+
* Normalize `$location.file` paths in CDS JSON files to use POSIX forward slashes.
5+
*
6+
* The SAP CDS compiler on Windows produces `$location.file` values with backslashes
7+
* (e.g. "srv\\service1.cds"), but the CodeQL CAP libraries expect forward slashes
8+
* (e.g. "srv/service1.cds"). This script normalizes all such paths in-place.
9+
*
10+
* This uses the same algorithm as `normalizeCdsJsonLocations` in
11+
* `extractors/cds/tools/src/filesystem.ts`, which has comprehensive unit tests.
12+
*
13+
* Usage:
14+
* node normalize-cds-json-paths.mjs <file1.cds.json> [file2.cds.json ...]
15+
*/
16+
17+
import { readFileSync, writeFileSync, existsSync, statSync } from 'fs';
18+
19+
/**
20+
* Recursively normalize $location.file values to forward slashes.
21+
*/
22+
function normalizeLocations(obj) {
23+
if (typeof obj !== 'object' || obj === null) return;
24+
25+
if (obj['$location']?.file && typeof obj['$location'].file === 'string') {
26+
obj['$location'].file = obj['$location'].file.split('\\').join('/');
27+
}
28+
29+
for (const key of ['definitions', 'elements', 'params', 'actions', 'functions', 'items', 'returns']) {
30+
const nested = obj[key];
31+
if (typeof nested === 'object' && nested !== null && !Array.isArray(nested)) {
32+
for (const child of Object.values(nested)) {
33+
normalizeLocations(child);
34+
}
35+
}
36+
}
37+
}
38+
39+
const args = process.argv.slice(2);
40+
if (args.length === 0) {
41+
console.log('Usage: node normalize-cds-json-paths.mjs <file.cds.json> [...]');
42+
process.exit(0);
43+
}
44+
45+
let changed = 0;
46+
for (const filePath of args) {
47+
if (!existsSync(filePath) || !statSync(filePath).isFile()) {
48+
console.error(`Skipping (not a file): ${filePath}`);
49+
continue;
50+
}
51+
52+
const raw = readFileSync(filePath, 'utf8');
53+
let data;
54+
try {
55+
data = JSON.parse(raw);
56+
} catch {
57+
console.error(`Skipping (invalid JSON): ${filePath}`);
58+
continue;
59+
}
60+
61+
normalizeLocations(data);
62+
const normalized = JSON.stringify(data, null, 2) + '\n';
63+
64+
if (normalized !== raw) {
65+
writeFileSync(filePath, normalized, 'utf8');
66+
console.log(`Normalized: ${filePath}`);
67+
changed++;
68+
}
69+
}
70+
71+
console.log(`Done. ${changed} file(s) normalized out of ${args.length} processed.`);

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,12 @@ import { basename, delimiter, dirname, join, relative, resolve, sep } from 'path
44
import { CdsCompilationResult } from './types';
55
import { getCdsVersion } from './version';
66
import { modelCdsJsonFile } from '../../constants';
7-
import { fileExists, dirExists, recursivelyRenameJsonFiles } from '../../filesystem';
7+
import {
8+
fileExists,
9+
dirExists,
10+
recursivelyRenameJsonFiles,
11+
normalizeLocationPathsInFile,
12+
} from '../../filesystem';
813
import { cdsExtractorLog } from '../../logging';
914
import { BasicCdsProject } from '../parser/types';
1015

@@ -216,6 +221,11 @@ function compileProject(
216221
cdsExtractorLog('info', `CDS compiler generated JSON to file: ${projectJsonOutPath}`);
217222
}
218223

224+
// Normalize $location.file paths to POSIX forward slashes.
225+
// The CDS compiler on Windows produces backslash paths (e.g. "srv\\service1.cds")
226+
// but CodeQL libraries expect forward slashes (e.g. "srv/service1.cds").
227+
normalizeLocationPathsInFile(projectJsonOutPath);
228+
219229
return {
220230
success: true,
221231
outputPath: projectJsonOutPath,

0 commit comments

Comments
 (0)