@sap/cds-compiler 2.5.2 → 2.11.0

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.
Files changed (102) hide show
  1. package/CHANGELOG.md +235 -9
  2. package/bin/cdsc.js +44 -27
  3. package/bin/cdsse.js +1 -0
  4. package/doc/CHANGELOG_BETA.md +37 -3
  5. package/lib/api/.eslintrc.json +2 -0
  6. package/lib/api/main.js +37 -123
  7. package/lib/api/options.js +27 -15
  8. package/lib/api/validate.js +34 -9
  9. package/lib/backends.js +9 -89
  10. package/lib/base/dictionaries.js +2 -1
  11. package/lib/base/keywords.js +32 -2
  12. package/lib/base/message-registry.js +73 -11
  13. package/lib/base/messages.js +86 -30
  14. package/lib/base/model.js +6 -6
  15. package/lib/base/optionProcessorHelper.js +56 -22
  16. package/lib/checks/defaultValues.js +27 -2
  17. package/lib/checks/elements.js +1 -6
  18. package/lib/checks/foreignKeys.js +0 -6
  19. package/lib/checks/managedWithoutKeys.js +17 -0
  20. package/lib/checks/nonexpandableStructured.js +38 -0
  21. package/lib/checks/onConditions.js +9 -45
  22. package/lib/checks/queryNoDbArtifacts.js +25 -7
  23. package/lib/checks/selectItems.js +29 -2
  24. package/lib/checks/types.js +26 -2
  25. package/lib/checks/unknownMagic.js +41 -0
  26. package/lib/checks/utils.js +61 -0
  27. package/lib/checks/validator.js +60 -7
  28. package/lib/compiler/assert-consistency.js +23 -7
  29. package/lib/compiler/base.js +65 -0
  30. package/lib/compiler/builtins.js +30 -1
  31. package/lib/compiler/checks.js +8 -5
  32. package/lib/compiler/definer.js +157 -133
  33. package/lib/compiler/index.js +89 -31
  34. package/lib/compiler/propagator.js +5 -2
  35. package/lib/compiler/resolver.js +375 -185
  36. package/lib/compiler/shared.js +49 -202
  37. package/lib/compiler/utils.js +173 -0
  38. package/lib/edm/annotations/genericTranslation.js +183 -187
  39. package/lib/edm/csn2edm.js +104 -108
  40. package/lib/edm/edm.js +18 -21
  41. package/lib/edm/edmPreprocessor.js +388 -146
  42. package/lib/edm/edmUtils.js +104 -34
  43. package/lib/gen/Dictionary.json +22 -0
  44. package/lib/gen/language.checksum +1 -1
  45. package/lib/gen/language.interp +28 -1
  46. package/lib/gen/language.tokens +79 -69
  47. package/lib/gen/languageLexer.interp +28 -1
  48. package/lib/gen/languageLexer.js +879 -805
  49. package/lib/gen/languageLexer.tokens +71 -62
  50. package/lib/gen/languageParser.js +5330 -4300
  51. package/lib/json/from-csn.js +110 -52
  52. package/lib/json/to-csn.js +434 -120
  53. package/lib/language/antlrParser.js +15 -3
  54. package/lib/language/errorStrategy.js +1 -0
  55. package/lib/language/genericAntlrParser.js +93 -26
  56. package/lib/language/language.g4 +172 -31
  57. package/lib/main.d.ts +216 -19
  58. package/lib/main.js +32 -7
  59. package/lib/model/api.js +78 -0
  60. package/lib/model/csnRefs.js +413 -149
  61. package/lib/model/csnUtils.js +286 -75
  62. package/lib/model/enrichCsn.js +50 -6
  63. package/lib/model/revealInternalProperties.js +22 -5
  64. package/lib/modelCompare/compare.js +39 -21
  65. package/lib/optionProcessor.js +35 -18
  66. package/lib/render/.eslintrc.json +4 -1
  67. package/lib/render/DuplicateChecker.js +9 -6
  68. package/lib/render/toCdl.js +121 -36
  69. package/lib/render/toHdbcds.js +148 -98
  70. package/lib/render/toSql.js +114 -43
  71. package/lib/render/utils/common.js +8 -13
  72. package/lib/render/utils/sql.js +3 -3
  73. package/lib/sql-identifier.js +6 -1
  74. package/lib/transform/db/assertUnique.js +5 -6
  75. package/lib/transform/db/constraints.js +281 -106
  76. package/lib/transform/db/draft.js +11 -8
  77. package/lib/transform/db/expansion.js +584 -0
  78. package/lib/transform/db/flattening.js +341 -0
  79. package/lib/transform/db/groupByOrderBy.js +2 -2
  80. package/lib/transform/db/transformExists.js +345 -65
  81. package/lib/transform/db/views.js +438 -0
  82. package/lib/transform/forHanaNew.js +131 -793
  83. package/lib/transform/forOdataNew.js +30 -24
  84. package/lib/transform/localized.js +39 -10
  85. package/lib/transform/odata/attachPath.js +19 -4
  86. package/lib/transform/odata/generateForeignKeyElements.js +11 -10
  87. package/lib/transform/odata/referenceFlattener.js +60 -39
  88. package/lib/transform/odata/sortByAssociationDependency.js +2 -2
  89. package/lib/transform/odata/structuralPath.js +72 -0
  90. package/lib/transform/odata/structureFlattener.js +19 -18
  91. package/lib/transform/odata/typesExposure.js +22 -12
  92. package/lib/transform/transformUtilsNew.js +144 -78
  93. package/lib/transform/translateAssocsToJoins.js +22 -27
  94. package/lib/transform/universalCsnEnricher.js +67 -0
  95. package/lib/utils/file.js +5 -14
  96. package/lib/utils/moduleResolve.js +6 -8
  97. package/lib/utils/term.js +65 -42
  98. package/lib/utils/timetrace.js +48 -26
  99. package/package.json +1 -1
  100. package/lib/json/walker.js +0 -26
  101. package/lib/transform/sqlite +0 -0
  102. package/lib/utils/string.js +0 -17
@@ -1,24 +1,22 @@
1
1
  'use strict'
2
2
 
3
3
  const { setProp, forEachGeneric, forEachDefinition, isBetaEnabled } = require('../base/model');
4
- var { handleMessages, makeMessageFunction } = require('../base/messages');
5
- var { linkToOrigin } = require('../compiler/shared');
4
+ var { makeMessageFunction } = require('../base/messages');
5
+ const { recompileX } = require('../compiler/index');
6
+ var { linkToOrigin } = require('../compiler/utils');
6
7
  const {compactModel, compactExpr} = require('../json/to-csn');
7
8
  const { deduplicateMessages } = require('../base/messages');
8
- const timetrace = require('../utils/timetrace');
9
+ const { timetrace } = require('../utils/timetrace');
9
10
  // Paths that start with an artifact of protected kind are special
10
11
  // either ignore them in QAT building or in path rewriting
11
12
  const internalArtifactKinds = ['builtin'/*, '$parameters'*/, 'param'];
12
13
 
13
14
  function translateAssocsToJoinsCSN(csn, options){
14
15
  timetrace.start('Recompiling model');
15
- let { augment } = require('../json/from-csn');
16
- // Append `.csn` to `.cds` files to indicate recompilation.
17
- const file = csn.$location && csn.$location.file.replace(/[.]cds$/, '.cds.csn') || '<recompile>.csn';
18
- let xsn = augment(csn, file, options);
19
- const { compileSourcesX } = require('../compiler');
20
16
  // Do not re-complain about localized
21
- const model = compileSourcesX( { [file]: xsn }, { ...options, $recompile: true } );
17
+ const compileOptions = { ...options, $skipNameCheck: true };
18
+ delete compileOptions.csnFlavor;
19
+ const model = recompileX(csn, compileOptions);
22
20
  timetrace.stop();
23
21
  timetrace.start('Translating associations to joins');
24
22
  translateAssocsToJoins(model, options);
@@ -46,9 +44,9 @@ function translateAssocsToJoinsCSN(csn, options){
46
44
  }
47
45
 
48
46
  // If A2J reports error - end! Continuing with a broken CSN makes no sense
49
- handleMessages(model, options);
47
+ makeMessageFunction(model, options).throwWithError();
50
48
  // FIXME: Move this somewhere more appropriate
51
- const compact = compactModel(model, options);
49
+ const compact = compactModel(model, compileOptions);
52
50
  return compact;
53
51
  }
54
52
 
@@ -181,7 +179,7 @@ function translateAssocsToJoins(model, inputOptions = {})
181
179
  let joinTree = query.from;
182
180
  for(let tan in query.$tableAliases)
183
181
  {
184
- if(!['$projection', '$self'].includes(tan)) // don't drive into $projection/$self tableAlias (yet)
182
+ if(query.$tableAliases[tan].kind !== '$self') // don't drive into $projection/$self tableAlias (yet)
185
183
  {
186
184
  let ta = query.$tableAliases[tan];
187
185
  joinTree = createJoinTree(env, joinTree, ta.$qat, 'left', '$qat', ta.$QA);
@@ -202,7 +200,7 @@ function translateAssocsToJoins(model, inputOptions = {})
202
200
  function createQAForFromClauseSubQuery(query, env)
203
201
  {
204
202
  for (let taName in query.$tableAliases) {
205
- if (!['$self', '$projection'].includes(taName)) {
203
+ if (query.$tableAliases[taName].kind !== '$self') {
206
204
  let ta = query.$tableAliases[taName];
207
205
  if(!ta.$QA) {
208
206
  ta.$QA = createQA(env, ta._origin, taName, undefined);
@@ -243,14 +241,6 @@ function translateAssocsToJoins(model, inputOptions = {})
243
241
  {
244
242
  art.$QA = createQA(env, art.target._artifact, art.name.id );
245
243
  art.$QA.mixin = true;
246
- /* Mark mixin definition to be _ignored:
247
- - If the mixin is used, it is now resolved into a join => definition vaporizes
248
- - If the mixin is published, forHana backend must create a __copy with rewritten
249
- $projection ON conditon and publish it with alias.
250
- - If the mixin is neither be used nor published it shall not be visible to the database
251
- (internal mixin).
252
- */
253
- art.$a2j = { _ignore: true };
254
244
  }
255
245
  });
256
246
  }
@@ -618,7 +608,7 @@ function translateAssocsToJoins(model, inputOptions = {})
618
608
  const id = this.id();
619
609
  if(elt) {
620
610
  let found = true;
621
- const epath = elt.split('.');
611
+ const epath = [elt];
622
612
  const epl = epath.length+offset;
623
613
  if(epl < path.length) {
624
614
  for(let i = 0; i < epl && found; i++) {
@@ -630,7 +620,7 @@ function translateAssocsToJoins(model, inputOptions = {})
630
620
  }
631
621
  if(id) {
632
622
  let found = true;
633
- const epath = id.split('.');
623
+ const epath = [id];
634
624
  const epl = epath.length+offset;
635
625
  if(epl < path.length) {
636
626
  for(let i = 0; i < epl && found; i++) {
@@ -745,9 +735,14 @@ function translateAssocsToJoins(model, inputOptions = {})
745
735
  function swapTableAliasesForFwdAssoc(fwdAssoc, srcAlias, tgtAlias) {
746
736
  let newSrcAlias = tgtAlias;
747
737
  let newTgtAlias = {};
748
- // first try to identify table alias for complex views or
749
- // redirected associations
750
- if(fwdAssoc._redirected && fwdAssoc._redirected.length) {
738
+ // first try to identify table alias for complex views or redirected associations
739
+ if(fwdAssoc._redirected && fwdAssoc._redirected.length &&
740
+ // redirected target must have a $QA
741
+ fwdAssoc._redirected[fwdAssoc._redirected.length-1].$QA &&
742
+ // $QA's artifact must either be same srcAlias artifact
743
+ (fwdAssoc._redirected[fwdAssoc._redirected.length-1].$QA._artifact === srcAlias._artifact ||
744
+ // OR original assoc is a mixin (then just use the $QA)
745
+ assoc.kind === 'mixin')) {
751
746
  newTgtAlias.id = fwdAssoc._redirected[fwdAssoc._redirected.length-1].$QA.name.id;
752
747
  newTgtAlias._artifact = fwdAssoc._redirected[fwdAssoc._redirected.length-1]._effectiveType;
753
748
  newTgtAlias._navigation = fwdAssoc._redirected[fwdAssoc._redirected.length-1].$QA.path[0]._navigation;
@@ -1400,7 +1395,7 @@ function translateAssocsToJoins(model, inputOptions = {})
1400
1395
 
1401
1396
  let [head, ...tail] = path;
1402
1397
 
1403
- if(['$projection', '$self'].includes(head.id) && tail.length) {
1398
+ if(['$projection', '$self'].includes(head.id) && tail.length && head._navigation.kind === '$self') {
1404
1399
  // make sure not to truncate tail
1405
1400
  if(tail.length > 1)
1406
1401
  [head, ...tail] = tail;
@@ -0,0 +1,67 @@
1
+ 'use strict';
2
+
3
+ const { forEachDefinition } = require('../base/model');
4
+ const {
5
+ applyTransformations,
6
+ cloneCsn,
7
+ getUtils,
8
+ isBuiltinType,
9
+ } = require('../model/csnUtils');
10
+
11
+ /**
12
+ * Loop through a universal CSN and enrich it with the properties
13
+ * from the source definition - modifies the input model in-place
14
+ *
15
+ * @param {CSN.Model} csn
16
+ * @param {CSN.Options} options
17
+ */
18
+ module.exports = function(csn, options) {
19
+ let { getOrigin, getFinalType, getFinalTypeDef } = getUtils(csn);
20
+ // User-defined structured types do not have the elements propagated any longer
21
+ // if there is no association among the elements. For that reason,
22
+ // as a first step propagate the elements of these
23
+ forEachDefinition(csn, (def) => {
24
+ if (def.kind === 'type' && def.type && !def.elements) {
25
+ const finalType = getFinalType(def.type);
26
+ if (isBuiltinType(finalType)) return;
27
+ const finalTypeDef = getFinalTypeDef(def.type);
28
+ if (finalTypeDef.elements)
29
+ def.elements = cloneCsn(finalTypeDef.elements, options);
30
+ }
31
+ });
32
+
33
+ // as a second step, loop through all the $origin properties in the model
34
+ // and propagate the properties from the origin definition
35
+ applyTransformations(csn, {
36
+ '$origin': (node, _$orign, $originValue, _path, parent, propName) => {
37
+ if (!node.kind) { // we do not want to replace whole definitions
38
+ if (Array.isArray($originValue))
39
+ propagatePropsFromOrigin(node, propName, parent);
40
+ else if ($originValue.$origin && Array.isArray($originValue.$origin)) {
41
+ // cover the case of query entity elements where we have own and ihnerited attributes/annotations
42
+ propagatePropsFromOrigin($originValue, propName, parent);
43
+ }
44
+
45
+ }
46
+ }
47
+ }, undefined, undefined, options);
48
+
49
+ function propagatePropsFromOrigin(member, memberName, construct) {
50
+ // TODO: shall the $origin be kept as part of the element?
51
+ const origin = getOrigin(member);
52
+ if (origin.kind) return;
53
+ if (member.elements && origin.type) {
54
+ delete member.$origin;
55
+ member.type = origin.type;
56
+ return;
57
+ }
58
+ let newMember = cloneCsn(origin, options);
59
+ // keep targets and keys of assoc, if it was redirected
60
+ if (origin.type === 'cds.Association') {
61
+ newMember.target = member.target || newMember.target;
62
+ newMember.keys = member.keys || newMember.keys;
63
+ }
64
+ // TODO: check if this works fine for items/returns/actions
65
+ construct[memberName] = newMember;
66
+ }
67
+ }
package/lib/utils/file.js CHANGED
@@ -15,16 +15,6 @@ function splitLines(src) {
15
15
  return src.split(/\r\n?|\n/);
16
16
  }
17
17
 
18
- /**
19
- * Change Windows style line endings to Unix style
20
- *
21
- * @param {string} src
22
- * @returns {string}
23
- */
24
- function normalizeLineEndings(src) {
25
- return (src && process.platform === 'win32') ? src.replace(/\r\n/g, '\n') : src;
26
- }
27
-
28
18
  /**
29
19
  * Returns filesystem utils readFile(), isFile(), realpath() for _CDS_ usage.
30
20
  * This includes a trace as well as usage of a file cache.
@@ -40,7 +30,7 @@ function cdsFs(fileCache, enableTrace) {
40
30
  const readFile = _wrapReadFileCached(fs.readFile);
41
31
  const readFileSync = _wrapReadFileCached((filename, enc, cb) => {
42
32
  try {
43
- cb(null, fs.readFileSync( filename, enc ));
33
+ cb(null, fs.readFileSync( filename, { encoding: enc } ));
44
34
  }
45
35
  catch (err) {
46
36
  cb(err, null);
@@ -82,7 +72,7 @@ function cdsFs(fileCache, enableTrace) {
82
72
  * Wraps the given reader into a cached environment including a trace.
83
73
  * The given @p reader must have the same signature as fs.readFile.
84
74
  *
85
- * @param {(filename: string, enc: string, cb: (err, data) => void) => void} reader
75
+ * @param {(filename: string, enc, cb: (err, data) => void) => void} reader
86
76
  */
87
77
  function _wrapReadFileCached( reader ) {
88
78
  return (filename, enc, cb) => {
@@ -103,7 +93,9 @@ function cdsFs(fileCache, enableTrace) {
103
93
  body.syscall = 'open';
104
94
  body.path = filename;
105
95
  }
106
- if (body instanceof Error) {
96
+ if (body && body.stack && body.message) {
97
+ // NOTE: checks for instanceof Error are not reliable if error
98
+ // created in different execution env
107
99
  traceFS( 'READFILE:cache-error:', filename, body.message );
108
100
  cb( body ); // no need for process.nextTick( cb, body ) with moduleResolve
109
101
  }
@@ -181,6 +173,5 @@ function cdsFs(fileCache, enableTrace) {
181
173
 
182
174
  module.exports = {
183
175
  splitLines,
184
- normalizeLineEndings,
185
176
  cdsFs,
186
177
  };
@@ -7,7 +7,6 @@
7
7
 
8
8
  const path = require('path');
9
9
 
10
- const { makeMessageFunction } = require('../base/messages');
11
10
  const { cdsFs } = require('./file');
12
11
 
13
12
  const DEFAULT_ENCODING = 'utf-8';
@@ -44,7 +43,7 @@ function adaptCdsModule(modulePath) {
44
43
  * @param {object} fileCache
45
44
  * @param {CSN.Options} options
46
45
  */
47
- function resolveModule( dep, fileCache, options ) {
46
+ function resolveModule( dep, fileCache, options, messageFunctions ) {
48
47
  const _fs = cdsFs(fileCache, options.traceFs);
49
48
  // let opts = { extensions, basedir: dep.basedir, preserveSymlinks: false };
50
49
  // `preserveSymlinks` option does not really work -> provide workaround anyway...
@@ -96,7 +95,7 @@ function resolveModule( dep, fileCache, options ) {
96
95
  }
97
96
  }
98
97
  }).catch( () => {
99
- _errorFileNotFound(dep, options);
98
+ _errorFileNotFound(dep, options, messageFunctions);
100
99
  return false;
101
100
  });
102
101
  }
@@ -107,7 +106,7 @@ function resolveModule( dep, fileCache, options ) {
107
106
  * @param {object} fileCache
108
107
  * @param {CSN.Options} options
109
108
  */
110
- function resolveModuleSync( dep, fileCache, options ) {
109
+ function resolveModuleSync( dep, fileCache, options, messageFunctions ) {
111
110
  const _fs = cdsFs(fileCache, options.traceFs);
112
111
  const opts = {
113
112
  extensions,
@@ -129,7 +128,7 @@ function resolveModuleSync( dep, fileCache, options ) {
129
128
  });
130
129
 
131
130
  if (error) {
132
- _errorFileNotFound(dep, options);
131
+ _errorFileNotFound(dep, options, messageFunctions);
133
132
  return false;
134
133
  }
135
134
 
@@ -148,7 +147,7 @@ function resolveModuleSync( dep, fileCache, options ) {
148
147
  }
149
148
 
150
149
  if (error) {
151
- _errorFileNotFound(dep, options);
150
+ _errorFileNotFound(dep, options, messageFunctions);
152
151
  return false;
153
152
  }
154
153
 
@@ -161,8 +160,7 @@ function resolveModuleSync( dep, fileCache, options ) {
161
160
  return result;
162
161
  }
163
162
 
164
- function _errorFileNotFound(dep, options) {
165
- const { error } = makeMessageFunction( null, options, 'compile' );
163
+ function _errorFileNotFound(dep, options, { error }) {
166
164
  if (dep.resolved) {
167
165
  let resolved = path.relative( dep.basedir, dep.resolved );
168
166
  if (options.testMode)
package/lib/utils/term.js CHANGED
@@ -2,8 +2,8 @@
2
2
  // This file is used for color output to stderr and stdout.
3
3
  // Use `term.error`, `term.warn` and `term.info` as they use color output
4
4
  // per default if the process runs in a TTY, i.e. stdout as well as
5
- // stderr are TTYs. stderr/stdout are no TTYs if they (for example)
6
- // are piped to another process or written to file:
5
+ // stderr are TTYs. stderr/stdout are no TTYs if they are
6
+ // (for example) piped into another process or written to file:
7
7
  //
8
8
  // node myApp.js # stdout.isTTY: true, stderr.isTTY: true
9
9
  // node myApp.js | cat # stdout.isTTY: undefined, stderr.isTTY: true
@@ -17,23 +17,9 @@
17
17
  const stderrHasColor = process.stderr.isTTY;
18
18
  const stdoutHasColor = process.stdout.isTTY;
19
19
 
20
- let hasColor = stdoutHasColor && stderrHasColor;
21
-
22
- module.exports.useColor = (mode) => {
23
- switch (mode) {
24
- case false:
25
- case 'never':
26
- hasColor = false;
27
- break;
28
- case true:
29
- case 'always':
30
- hasColor = true;
31
- break;
32
- default:
33
- hasColor = stdoutHasColor && stderrHasColor;
34
- break;
35
- }
36
- };
20
+ // Note: We require both stderr and stdout to be TTYs, as we don't
21
+ // know (in our exported functions) where the text will end up.
22
+ const hasColorShell = stdoutHasColor && stderrHasColor;
37
23
 
38
24
  // https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences
39
25
  const t = {
@@ -47,29 +33,66 @@ const t = {
47
33
  cyan: '\x1b[36m', // Foreground Cyan
48
34
  };
49
35
 
50
- const as = (codes, o) => (hasColor ? (codes + o + t.reset) : (`${ o }`));
36
+ function term(useColor = 'auto') {
37
+ let hasColor = hasColorShell;
38
+ changeColorMode(useColor);
51
39
 
52
- const asError = o => as(t.red + t.bold, o);
53
- const asWarning = o => as(t.yellow, o);
54
- const asInfo = o => as(t.green, o);
55
- const asHelp = o => as(t.cyan, o);
56
- module.exports.underline = o => as(t.underline, o);
57
- module.exports.bold = o => as(t.bold, o);
58
-
59
- module.exports.asSeverity = (severity, msg) => {
60
- switch ((`${ severity }`).toLowerCase()) {
61
- case 'error': return asError(msg);
62
- case 'warning': return asWarning(msg);
63
- case 'info': return asInfo(msg);
64
- case 'help': return asHelp(msg);
65
- // or e.g. 'none'
66
- default: return msg;
40
+ function changeColorMode(mode) {
41
+ switch (mode) {
42
+ case false:
43
+ case 'never':
44
+ hasColor = false;
45
+ break;
46
+ case true:
47
+ case 'always':
48
+ hasColor = true;
49
+ break;
50
+ default:
51
+ // Note: See also: https://no-color.org/
52
+ // > Command-line software which adds ANSI color to its output by default
53
+ // > should check for the presence of a `NO_COLOR` environment variable
54
+ // > that, when present (regardless of its value), prevents the addition
55
+ // > of ANSI color.
56
+ // Note: To be able to disable colors in tests, we check the environment
57
+ // variable here again.
58
+ hasColor = hasColorShell && (process.env.NO_COLOR === undefined);
59
+ break;
60
+ }
67
61
  }
68
- };
69
62
 
70
- module.exports.codes = t;
71
- module.exports.as = as;
72
- module.exports.error = asError;
73
- module.exports.warn = asWarning;
74
- module.exports.info = asInfo;
75
- module.exports.help = asHelp;
63
+ const as = (codes, o) => (hasColor ? (codes + o + t.reset) : (`${ o }`));
64
+
65
+ const asError = o => as(t.red + t.bold, o);
66
+ const asWarning = o => as(t.yellow, o);
67
+ const asInfo = o => as(t.green, o);
68
+ const asHelp = o => as(t.cyan, o);
69
+
70
+ const underline = o => as(t.underline, o);
71
+ const bold = o => as(t.bold, o);
72
+
73
+ const asSeverity = (severity, msg) => {
74
+ switch ((`${ severity }`).toLowerCase()) {
75
+ case 'error': return asError(msg);
76
+ case 'warning': return asWarning(msg);
77
+ case 'info': return asInfo(msg);
78
+ case 'help': return asHelp(msg);
79
+ // or e.g. 'none'
80
+ default: return msg;
81
+ }
82
+ };
83
+
84
+ return {
85
+ changeColorMode,
86
+ as,
87
+ underline,
88
+ bold,
89
+
90
+ severity: asSeverity,
91
+ error: asError,
92
+ warn: asWarning,
93
+ info: asInfo,
94
+ help: asHelp,
95
+ };
96
+ }
97
+
98
+ module.exports = { term };
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * @class TimeTrace
7
7
  */
8
- class TimeTrace {
8
+ class StopWatch {
9
9
  /**
10
10
  * Creates an instance of TimeTrace.
11
11
  * @param {string} id
@@ -13,29 +13,46 @@ class TimeTrace {
13
13
  * @memberOf TimeTrace
14
14
  */
15
15
  constructor(id) {
16
- let startTime;
17
- /**
18
- * Start measuring.
19
- *
20
- * @param {number} indent
21
- */
22
- this.start = function start(indent) {
23
- // eslint-disable-next-line no-console
24
- console.error(`${ ' '.repeat((indent) * 2) }${ id } started`);
25
- startTime = process.hrtime();
26
- };
16
+ this.id = id;
17
+ // eslint-disable-next-line no-multi-assign
18
+ this.startTime = this.lapTime = process.hrtime();
19
+ }
27
20
 
28
- /**
29
- * Stop measuring and log the result
30
- *
31
- * @param {number} indent
21
+ /**
22
+ * Start watch.
32
23
  */
33
- this.stop = function stop(indent) {
34
- const endTime = process.hrtime(startTime);
35
- const base = `${ ' '.repeat(indent * 2) }${ id } took:`;
36
- // eslint-disable-next-line no-console
37
- console.error( `${ base }${ ' '.repeat(60 - base.length) } %ds %dms`, endTime[0], endTime[1] / 1000000);
38
- };
24
+ start() {
25
+ // eslint-disable-next-line no-multi-assign
26
+ this.startTime = this.lapTime = process.hrtime();
27
+ }
28
+
29
+ /**
30
+ * Stop and return delta T
31
+ * but do not set start time
32
+ */
33
+ stop() {
34
+ return process.hrtime(this.startTime);
35
+ }
36
+
37
+ /**
38
+ * return lap time
39
+ */
40
+ lap() {
41
+ const dt = process.hrtime(this.lapTime);
42
+ this.lapTime = process.hrtime();
43
+ return dt;
44
+ }
45
+
46
+ // stop as sec.ns float
47
+ stopInFloatSecs() {
48
+ const dt = this.stop();
49
+ return dt[0] + dt[1] / 1000000000;
50
+ }
51
+
52
+ // lap as sec.ns float
53
+ lapInFloatSecs() {
54
+ const dt = this.lap();
55
+ return dt[0] + dt[1] / 1000000000;
39
56
  }
40
57
  }
41
58
 
@@ -67,9 +84,11 @@ class TimeTracer {
67
84
  */
68
85
  start(id) {
69
86
  try {
70
- const b = new TimeTrace(id);
87
+ const b = new StopWatch(id);
71
88
  this.traceStack.push(b);
72
- b.start(this.traceStack.length - 1);
89
+ b.start();
90
+ // eslint-disable-next-line no-console
91
+ console.error(`${ ' '.repeat((this.traceStack.length - 1) * 2) }${ id } started`);
73
92
  }
74
93
  catch (e) {
75
94
  // eslint-disable-next-line no-console
@@ -86,7 +105,10 @@ class TimeTracer {
86
105
  stop() {
87
106
  try {
88
107
  const current = this.traceStack.pop();
89
- current.stop(this.traceStack.length);
108
+ const dT = current.stop();
109
+ const base = `${ ' '.repeat(this.traceStack.length * 2) }${ current.id } took:`;
110
+ // eslint-disable-next-line no-console
111
+ console.error( `${ base }${ ' '.repeat(60 - base.length) } %ds %dms`, dT[0], dT[1] / 1000000);
90
112
  }
91
113
  catch (e) {
92
114
  // eslint-disable-next-line no-console
@@ -101,4 +123,4 @@ const ignoreTimeTrace = {
101
123
  };
102
124
 
103
125
  const doTimeTrace = process && process.env && process.env.CDSC_TIMETRACING !== undefined;
104
- module.exports = doTimeTrace ? new TimeTracer() : ignoreTimeTrace;
126
+ module.exports = { timetrace: (doTimeTrace ? new TimeTracer() : ignoreTimeTrace), StopWatch };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sap/cds-compiler",
3
- "version": "2.5.2",
3
+ "version": "2.11.0",
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)",
@@ -1,26 +0,0 @@
1
- /**
2
- * Walker module provides non-recursive tree walkers with different flavours
3
- * @module json/walker
4
- */
5
-
6
- /**
7
- * Callback of the forEach function called for each node it walks
8
- * @callback forEachCallback
9
- * @param {string} name of the node
10
- * @param {object} node
11
- */
12
-
13
- /**
14
- * Loops over all elements in an object and calls the specified callback(key,obj)
15
- * @param {object} obj
16
- * @param {forEachCallback} callback
17
- */
18
- function forEach(obj, callback) {
19
- for(var key in obj) {
20
- callback(key, obj[key]);
21
- }
22
- }
23
-
24
- module.exports = {
25
- forEach,
26
- }
File without changes
@@ -1,17 +0,0 @@
1
- 'use strict';
2
-
3
- // String utils
4
-
5
- /**
6
- * Removes duplicate entries from the given string array.
7
- *
8
- * @param {string[]} strings Array of strings with duplicates
9
- * @returns {string[]} strings New array with unique strings
10
- */
11
- function uniqueStrings(strings) {
12
- return [ ...new Set(strings) ];
13
- }
14
-
15
- module.exports = {
16
- uniqueStrings,
17
- };