@sap/cds-compiler 6.9.1 → 6.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -13,6 +13,16 @@ we might not list every change in its behavior here.
13
13
  Productive code should never require a `beta` flag to be set, and
14
14
  might use a deprecated flag only for a limited period of time.
15
15
 
16
+ ## Version 6.9.2 - 2026-05-08
17
+
18
+ ### Bug Fixes
19
+
20
+ - **api:** when the environment variable `CDSC_TRACE_API` is set,
21
+ the compiler writes a trace for calls of API functions;
22
+ it now has more information, and also traces the exit of the API function.
23
+
24
+
25
+
16
26
  ## Version 6.9.1 - 2026-05-05
17
27
 
18
28
  ### Bug Fixes
package/lib/api/main.js CHANGED
@@ -1169,7 +1169,7 @@ function publishCsnProcessor( processor, _name ) {
1169
1169
  * @returns {any} What ever the processor returns
1170
1170
  */
1171
1171
  function api( csn, options = {}, ...args ) {
1172
- trace.traceApi(_name, options);
1172
+ trace.call(_name, options, csn);
1173
1173
  const originalMessageLength = options.messages?.length;
1174
1174
  try {
1175
1175
  const messageFunctions = messages.makeMessageFunction(csn, options, _name);
@@ -1184,6 +1184,7 @@ function publishCsnProcessor( processor, _name ) {
1184
1184
  timetrace.timetrace.start(_name);
1185
1185
  const result = processor( csn, options, messageFunctions, ...args );
1186
1186
  timetrace.timetrace.stop(_name);
1187
+ trace.exit(_name, result);
1187
1188
  return result;
1188
1189
  }
1189
1190
  catch (err) {
@@ -1200,6 +1201,7 @@ function publishCsnProcessor( processor, _name ) {
1200
1201
  if (originalMessageLength !== undefined)
1201
1202
  options.messages.length = originalMessageLength;
1202
1203
 
1204
+ trace.log( 'recompile CSN and retry backend' );
1203
1205
  const messageFunctions = messages.makeMessageFunction( csn, options, _name );
1204
1206
  const recompileMsg = messageFunctions.info( 'api-recompiled-csn', location.emptyLocation('csn.json'), {},
1205
1207
  'CSN input had to be recompiled' );
@@ -1211,7 +1213,10 @@ function publishCsnProcessor( processor, _name ) {
1211
1213
  const xsn = compiler.recompileX(csn, options);
1212
1214
  const recompiledCsn = toCsn.compactModel(xsn);
1213
1215
  messageFunctions.setModel(recompiledCsn);
1214
- return processor( recompiledCsn, options, messageFunctions, ...args );
1216
+ const result = processor( recompiledCsn, options, messageFunctions, ...args );
1217
+ timetrace.timetrace.stop(_name);
1218
+ trace.exit(_name, result);
1219
+ return result;
1215
1220
  }
1216
1221
  }
1217
1222
  }
@@ -16,6 +16,7 @@ const {
16
16
  const _messageIdsWithExplanation = require('../../share/messages/message-explanations.json').messages;
17
17
  const { analyseCsnPath, traverseQuery } = require('../base/csnRefs');
18
18
  const { CompilerAssertion } = require('./error');
19
+ const trace = require('./trace');
19
20
  const { getArtifactName } = require('../compiler/base');
20
21
  const { cdlNewLineRegEx } = require('../language/textUtils');
21
22
  const meta = require('./meta');
@@ -567,8 +568,10 @@ function makeMessageFunction( model, options, _moduleName = null ) {
567
568
  }
568
569
 
569
570
  function throwWithError() {
570
- if (hasNewError)
571
+ if (hasNewError) {
572
+ trace.log( `stop compilation with ${ messages.length } messages` );
571
573
  throw new CompilationError(messages, options.attachValidNames && model);
574
+ }
572
575
  }
573
576
 
574
577
  /**
@@ -583,8 +586,10 @@ function makeMessageFunction( model, options, _moduleName = null ) {
583
586
  if (!messages || !messages.length)
584
587
  return;
585
588
  const hasError = options.testMode ? hasNonDowngradableErrors : hasErrors;
586
- if (hasError( messages, moduleName, options ))
589
+ if (hasError( messages, moduleName, options )) {
590
+ trace.log( `stop compilation with ${ messages.length } messages` );
587
591
  throw new CompilationError(messages, options.attachValidNames && model);
592
+ }
588
593
  }
589
594
 
590
595
  /**
package/lib/base/trace.js CHANGED
@@ -5,33 +5,87 @@ const shouldTraceApi = process?.env?.CDSC_TRACE_API;
5
5
 
6
6
  /**
7
7
  * Placeholder for disabled tracing (no-op).
8
- *
9
- * @param {string} apiName API name
10
- * @param {object} options Options passed to the API.
11
- * @param {...any} [args] Arguments to be logged to stderr
12
8
  */
13
- // eslint-disable-next-line no-unused-vars
14
- function noOp( apiName, options, ...args ) {
9
+ function noOp() {
15
10
  // no-op
16
11
  }
17
12
 
18
13
  /**
19
- * Print args to stderr if CDSC_TRACE_API is set
20
- *
21
- * @param {string} apiName API name
22
- * @param {object} options Options passed to the API.
23
- * @param {...any} [args] Arguments to be logged to stderr
14
+ * Print trace info to stderr when calling an API function
24
15
  */
25
- function traceApi( apiName, options, ...args ) {
26
- const optStr = typeof options === 'object' ? JSON.stringify(options, null, 2) : options;
27
- const argsStr = args.map(val => JSON.stringify(val)).join(', ');
28
- const rest = args.length > 0 ? ` | ${ argsStr }` : '';
29
- // Local require: Only load on-demand, not when tracing is disabled.
16
+ function call( apiName, options, csn, files ) {
30
17
  const { version } = require('../../package.json');
18
+ const now = (new Date( Date.now() )).toISOString();
19
+ const args = (files || csn)
20
+ ? `${ optionsString( options ) } on ${ filesInfo( files ) || csnInfo( csn ) }`
21
+ : optionsString( options );
31
22
  // eslint-disable-next-line no-console
32
- console.error( `CDSC_TRACE_API | ${ version } | ${ apiName }() | options: ${ optStr }${ rest }`);
23
+ console.error( 'CDSC_TRACE_API: at %s, call %s() of v%s with options %s',
24
+ now, apiName, version, args );
33
25
  }
34
26
 
35
- module.exports = {
36
- traceApi: shouldTraceApi ? traceApi : noOp,
37
- };
27
+ /**
28
+ * Print trace info to stderr when exiting an API function
29
+ */
30
+ function exit( apiName, result ) {
31
+ const now = (new Date( Date.now() )).toISOString();
32
+ const info = (result?.definitions || result?.extensions)
33
+ ? csnInfo( result )
34
+ : `a result of type ${ typeof result }`;
35
+ // eslint-disable-next-line no-console
36
+ console.error( 'CDSC_TRACE_API: at %s, exit %s() and return %s',
37
+ now, apiName, info );
38
+ }
39
+
40
+ /**
41
+ * Print trace info to stderr for miscellaneous use cases
42
+ */
43
+ function log( info ) {
44
+ const now = (new Date( Date.now() )).toISOString();
45
+ // eslint-disable-next-line no-console
46
+ console.error( 'CDSC_TRACE_API: at %s, %s', now, info );
47
+ }
48
+
49
+ function optionsString( obj ) {
50
+ if (!obj || typeof obj !== 'object')
51
+ return obj.toString();
52
+ try {
53
+ if (Array.isArray( obj.messages ) && obj.messages.length) {
54
+ const messages = {};
55
+ for (const msg of obj.messages)
56
+ messages[msg.severity] = (messages[msg.severity] || 0) + 1;
57
+ obj = { ...obj, messages };
58
+ }
59
+ return JSON.stringify( obj, null, 2 );
60
+ }
61
+ catch (err) {
62
+ return err.toString();
63
+ }
64
+ }
65
+
66
+ function filesInfo( files ) {
67
+ if (!files)
68
+ return files;
69
+ if (!Array.isArray( files ))
70
+ files = Object.keys( files );
71
+ return files.length ? [ 'files', ...files ].join( '\n ') : 'no files';
72
+ }
73
+
74
+ function csnInfo( csn ) {
75
+ if (!csn || typeof csn !== 'object' || Array.isArray( csn ))
76
+ return `some value of type ${ typeof csn }`;
77
+ try {
78
+ JSON.stringify( csn );
79
+ const defs = csn.definitions ? Object.keys( csn.definitions ).length : 'no';
80
+ const exts = csn.extensions ? csn.extensions.length : 'no';
81
+ const flavor = csn.meta?.flavor || csn.meta?.compilerCsnFlavor || 'unknown';
82
+ return `a CSN of flavor '${ flavor }' with ${ defs } definitions and ${ exts } extensions`;
83
+ }
84
+ catch (err) {
85
+ return `a CORRUPTED CSN (${ err.toString() })`;
86
+ }
87
+ }
88
+
89
+ module.exports = (shouldTraceApi)
90
+ ? { call, exit, log }
91
+ : { call: noOp, exit: noOp, log: noOp };
package/lib/main.js CHANGED
@@ -16,7 +16,7 @@
16
16
 
17
17
  const lazyload = require('./utils/lazyload')( module );
18
18
 
19
- const { traceApi } = require('./base/trace');
19
+ const trace = require('./base/trace');
20
20
 
21
21
  const snapi = lazyload('./api/main');
22
22
  const csnUtils = lazyload('./model/csnUtils');
@@ -40,6 +40,7 @@ const meta = lazyload('./base/meta');
40
40
  const toCsn = lazyload('./json/to-csn');
41
41
 
42
42
  function parseCdl( cdlSource, filename, options = {} ) {
43
+ trace.call( 'parse.cdl', options );
43
44
  options = Object.assign( {}, options, { parseCdl: true } );
44
45
  const sources = Object.create(null);
45
46
  /** @type {XSN.Model} */
@@ -56,7 +57,7 @@ function parseCdl( cdlSource, filename, options = {} ) {
56
57
  define( model );
57
58
  finalizeParseCdl( model );
58
59
  messageFunctions.throwWithError();
59
- return toCsn.compactModel( model );
60
+ return compactAndTrace( model, 'parse.cdl' );
60
61
  }
61
62
 
62
63
  function parseCql( cdlSource, filename = '<query>.cds', options = {} ) {
@@ -75,6 +76,12 @@ function parseExpr( cdlSource, filename = '<expr>.cds', options = {} ) {
75
76
  return toCsn.compactExpr( xsn );
76
77
  }
77
78
 
79
+ function compactAndTrace( xsn, apiName = 'compile' ) {
80
+ const csn = toCsn.compactModel( xsn );
81
+ trace.exit( apiName, csn );
82
+ return csn;
83
+ }
84
+
78
85
  // FIXME: The implementation of those functions that delegate to 'backends'
79
86
  // should probably move here
80
87
  // ATTENTION: Keep in sync with main.d.ts!
@@ -82,16 +89,19 @@ module.exports = {
82
89
  // Compiler
83
90
  version: () => meta.version(),
84
91
  compile: (filenames, dir, options, fileCache) => { // main function
85
- traceApi( 'compile', options );
86
- return compiler.compileX(filenames, dir, options, fileCache).then(toCsn.compactModel);
92
+ trace.call( 'compile', options, null, filenames );
93
+ return compiler.compileX( filenames, dir, options, fileCache )
94
+ .then( compactAndTrace );
87
95
  },
88
96
  compileSync: (filenames, dir, options, fileCache) => { // main function
89
- traceApi('compileSync', options);
90
- return toCsn.compactModel(compiler.compileSyncX(filenames, dir, options, fileCache));
97
+ trace.call( 'compileSync', options, null, filenames );
98
+ const xsn = compiler.compileSyncX( filenames, dir, options, fileCache );
99
+ return compactAndTrace( xsn, 'compileSync' );
91
100
  },
92
101
  compileSources: (sourcesDict, options) => { // main function
93
- traceApi('compileSources', options);
94
- return toCsn.compactModel(compiler.compileSourcesX(sourcesDict, options));
102
+ trace.call( 'compileSources', options, null, sourcesDict );
103
+ const xsn = compiler.compileSourcesX( sourcesDict, options );
104
+ return compactAndTrace( xsn, 'compileSources' );
95
105
  },
96
106
  compactModel: csn => csn, // for easy v2 migration
97
107
  get CompilationError() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sap/cds-compiler",
3
- "version": "6.9.1",
3
+ "version": "6.9.2",
4
4
  "description": "CDS (Core Data Services) compiler and backends",
5
5
  "homepage": "https://cap.cloud.sap/",
6
6
  "author": "SAP SE (https://www.sap.com)",