@sap/cds-compiler 2.10.2 → 2.11.4
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 +90 -5
- package/bin/.eslintrc.json +1 -2
- package/bin/cds_update_identifiers.js +3 -1
- package/bin/cdsc.js +49 -25
- package/bin/cdsse.js +1 -0
- package/bin/cdsv2m.js +3 -2
- package/doc/CHANGELOG_BETA.md +10 -0
- package/lib/api/.eslintrc.json +2 -0
- package/lib/api/main.js +8 -36
- package/lib/api/options.js +15 -6
- package/lib/api/validate.js +30 -3
- package/lib/backends.js +12 -13
- package/lib/base/dictionaries.js +2 -1
- package/lib/base/keywords.js +3 -2
- package/lib/base/message-registry.js +34 -10
- package/lib/base/messages.js +38 -18
- package/lib/base/model.js +5 -4
- package/lib/base/optionProcessorHelper.js +57 -23
- package/lib/checks/emptyOrOnlyVirtual.js +2 -2
- package/lib/checks/selectItems.js +4 -0
- package/lib/checks/unknownMagic.js +6 -3
- package/lib/compiler/assert-consistency.js +9 -2
- package/lib/compiler/base.js +65 -0
- package/lib/compiler/builtins.js +62 -16
- package/lib/compiler/checks.js +2 -1
- package/lib/compiler/definer.js +66 -108
- package/lib/compiler/index.js +29 -29
- package/lib/compiler/propagator.js +5 -2
- package/lib/compiler/resolver.js +225 -58
- package/lib/compiler/shared.js +53 -229
- package/lib/compiler/utils.js +184 -0
- package/lib/edm/annotations/genericTranslation.js +1 -1
- package/lib/edm/csn2edm.js +3 -2
- package/lib/edm/edmPreprocessor.js +34 -38
- package/lib/edm/edmUtils.js +3 -3
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +17 -1
- package/lib/gen/language.tokens +79 -73
- package/lib/gen/languageLexer.interp +19 -1
- package/lib/gen/languageLexer.js +779 -731
- package/lib/gen/languageLexer.tokens +71 -65
- package/lib/gen/languageParser.js +4668 -4072
- package/lib/json/from-csn.js +10 -10
- package/lib/json/to-csn.js +228 -47
- package/lib/language/antlrParser.js +11 -0
- package/lib/language/errorStrategy.js +26 -8
- package/lib/language/genericAntlrParser.js +73 -14
- package/lib/language/language.g4 +79 -3
- package/lib/main.d.ts +215 -18
- package/lib/main.js +3 -1
- package/lib/model/api.js +2 -2
- package/lib/model/csnRefs.js +117 -33
- package/lib/model/csnUtils.js +65 -133
- package/lib/model/enrichCsn.js +62 -37
- package/lib/model/revealInternalProperties.js +25 -8
- package/lib/model/sortViews.js +8 -1
- package/lib/modelCompare/compare.js +2 -1
- package/lib/optionProcessor.js +33 -18
- package/lib/render/.eslintrc.json +1 -2
- package/lib/render/DuplicateChecker.js +1 -1
- package/lib/render/toCdl.js +15 -8
- package/lib/render/toHdbcds.js +26 -49
- package/lib/render/toSql.js +61 -39
- package/lib/render/utils/common.js +1 -1
- package/lib/transform/db/applyTransformations.js +189 -0
- package/lib/transform/db/constraints.js +273 -119
- package/lib/transform/db/draft.js +3 -2
- package/lib/transform/db/expansion.js +6 -4
- package/lib/transform/db/flattening.js +19 -3
- package/lib/transform/db/transformExists.js +102 -9
- package/lib/transform/db/views.js +485 -0
- package/lib/transform/forHanaNew.js +93 -448
- package/lib/transform/forOdataNew.js +9 -2
- package/lib/transform/localized.js +2 -0
- package/lib/transform/odata/structuralPath.js +1 -5
- package/lib/transform/transformUtilsNew.js +22 -8
- package/lib/transform/translateAssocsToJoins.js +7 -15
- package/lib/utils/file.js +11 -5
- package/lib/utils/term.js +65 -42
- package/lib/utils/timetrace.js +48 -26
- package/package.json +1 -1
- package/lib/transform/db/helpers.js +0 -58
|
@@ -22,7 +22,7 @@ const { flattenCSN } = require('./odata/structureFlattener');
|
|
|
22
22
|
const generateForeignKeys = require('./odata/generateForeignKeyElements');
|
|
23
23
|
const expandStructKeysInAssociations = require('./odata/expandStructKeysInAssociations');
|
|
24
24
|
const expandToFinalBaseType = require('./odata/toFinalBaseType');
|
|
25
|
-
const timetrace = require('../utils/timetrace');
|
|
25
|
+
const { timetrace } = require('../utils/timetrace');
|
|
26
26
|
const { attachPath } = require('./odata/attachPath');
|
|
27
27
|
const enrichUniversalCsn = require('./universalCsnEnricher');
|
|
28
28
|
|
|
@@ -191,7 +191,11 @@ function transform4odataWithCsn(inputModel, options) {
|
|
|
191
191
|
generateForeignKeys(csn, options, referenceFlattener, csnUtils, error, isExternalServiceMember);
|
|
192
192
|
|
|
193
193
|
// Apply default type facets as set by options
|
|
194
|
-
// Flatten on-conditions in unmanaged associations
|
|
194
|
+
// Flatten on-conditions in unmanaged associations
|
|
195
|
+
/* FIXME (HJB): Is this comment still correct? processOnCond only strips $self
|
|
196
|
+
We should not remove $self prefixes in structured OData to not
|
|
197
|
+
interfer with path resolution
|
|
198
|
+
*/
|
|
195
199
|
// This must be done before all the draft logic as all
|
|
196
200
|
// composition targets are annotated with @odata.draft.enabled in this step
|
|
197
201
|
forEachDefinition(csn, [ setDefaultTypeFacets, processOnCond ], { skipArtifact: isExternalServiceMember });
|
|
@@ -569,6 +573,9 @@ function transform4odataWithCsn(inputModel, options) {
|
|
|
569
573
|
// CDXCORE-481
|
|
570
574
|
// (4.5) If the member is an association whose target has @cds.odata.valuelist annotate it
|
|
571
575
|
// with @Common.ValueList.viaAssociation.
|
|
576
|
+
/*
|
|
577
|
+
FIXME (HJB): Comment outdated: Anno propagation to FKs is done in EdmPreprocessor
|
|
578
|
+
*/
|
|
572
579
|
// This must be done before foreign keys are calculated and the annotations are propagated
|
|
573
580
|
// to them. This will make sure that association and all its foreign keys are annotated with
|
|
574
581
|
// Common.ValueList in the final EDM.
|
|
@@ -698,6 +698,8 @@ function copyPersistenceAnnotations(target, source) {
|
|
|
698
698
|
* @param {CSN.Options} options
|
|
699
699
|
*/
|
|
700
700
|
function hasExistingLocalizationViews(csn, options) {
|
|
701
|
+
if (!csn || !csn.definitions)
|
|
702
|
+
return false;
|
|
701
703
|
const firstLocalizedView = Object.keys(csn.definitions).find(isInLocalizedNamespace);
|
|
702
704
|
if (firstLocalizedView) {
|
|
703
705
|
const { info } = makeMessageFunction(csn, options);
|
|
@@ -10,7 +10,7 @@ const structuralNodeHandlers = {
|
|
|
10
10
|
returns: traverseTyped,
|
|
11
11
|
on: traverseArray,
|
|
12
12
|
keys: traverseArray,
|
|
13
|
-
ref:
|
|
13
|
+
ref: traverseArray,
|
|
14
14
|
query: traverseTyped,
|
|
15
15
|
SELECT: traverseTyped,
|
|
16
16
|
SET: traverseTyped,
|
|
@@ -33,10 +33,6 @@ function structuralPath(csn, path) {
|
|
|
33
33
|
return traverseDict(csn.definitions, path, 1, ['definitions']);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
function traverseRef(obj, path, index, typeStack) {
|
|
37
|
-
return traverseArray(obj, path, index, typeStack);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
36
|
function traverseArray(obj, path, index, typeStack) {
|
|
41
37
|
if(!Array.isArray(obj)) return typeStack;
|
|
42
38
|
const name = path[index];
|
|
@@ -80,6 +80,14 @@ function getTransformers(model, options, pathDelimiter = '_') {
|
|
|
80
80
|
else if(defStrLen5k)
|
|
81
81
|
element.length = 5000;
|
|
82
82
|
}
|
|
83
|
+
if (element.type === 'cds.Binary' && element.length === undefined) {
|
|
84
|
+
if(options.defaultBinaryLength) {
|
|
85
|
+
element.length = options.defaultBinaryLength;
|
|
86
|
+
setProp(element, '$default', true);
|
|
87
|
+
}
|
|
88
|
+
else if(defStrLen5k)
|
|
89
|
+
element.length = 5000;
|
|
90
|
+
}
|
|
83
91
|
/*
|
|
84
92
|
if (element.type === 'cds.Decimal' && element.precision === undefined && options.precision) {
|
|
85
93
|
element.precision = options.precision;
|
|
@@ -343,6 +351,8 @@ function getTransformers(model, options, pathDelimiter = '_') {
|
|
|
343
351
|
|
|
344
352
|
/**
|
|
345
353
|
* Copy properties of the referenced type, but don't resolve to the final base type.
|
|
354
|
+
*
|
|
355
|
+
* Do not copy the length if it was just set via the default-value.
|
|
346
356
|
*
|
|
347
357
|
* @param {any} node Node to copy to
|
|
348
358
|
* @returns {void}
|
|
@@ -1084,16 +1094,16 @@ function getTransformers(model, options, pathDelimiter = '_') {
|
|
|
1084
1094
|
function expandStructsInExpression(csn, options = {}) {
|
|
1085
1095
|
applyTransformations(csn, {
|
|
1086
1096
|
'on': (parent, name, on, path) => {
|
|
1087
|
-
parent.on = expand(parent.on, path);
|
|
1097
|
+
parent.on = expand(parent.on, path.concat(name));
|
|
1088
1098
|
},
|
|
1089
1099
|
'having': (parent, name, having, path) => {
|
|
1090
|
-
parent.having = expand(parent.having, path);
|
|
1100
|
+
parent.having = expand(parent.having, path.concat(name));
|
|
1091
1101
|
},
|
|
1092
1102
|
'where': (parent, name, where, path) => {
|
|
1093
|
-
parent.where = expand(parent.where, path);
|
|
1103
|
+
parent.where = expand(parent.where, path.concat(name));
|
|
1094
1104
|
},
|
|
1095
1105
|
'xpr': (parent, name, xpr, path) => {
|
|
1096
|
-
parent.xpr = expand(parent.xpr, path);
|
|
1106
|
+
parent.xpr = expand(parent.xpr, path.concat(name));
|
|
1097
1107
|
}
|
|
1098
1108
|
}, undefined, undefined, options);
|
|
1099
1109
|
|
|
@@ -1111,17 +1121,21 @@ function getTransformers(model, options, pathDelimiter = '_') {
|
|
|
1111
1121
|
if(i < expr.length-2)
|
|
1112
1122
|
{
|
|
1113
1123
|
const [lhs, op, rhs] = expr.slice(i);
|
|
1124
|
+
|
|
1125
|
+
// we might have to ad-hoc resolve a ref, since handleExists is run before hand and generates new refs.
|
|
1126
|
+
const lhsArt = lhs._art || lhs.ref && !lhs.$scope && inspectRef(location.concat(i)).art;
|
|
1127
|
+
const rhsArt = rhs._art || rhs.ref && !rhs.$scope && inspectRef(location.concat(i+2)).art;
|
|
1114
1128
|
// lhs & rhs must be expandable types (structures or managed associations)
|
|
1115
|
-
if(
|
|
1129
|
+
if(lhsArt && rhsArt &&
|
|
1116
1130
|
lhs.ref && rhs.ref &&
|
|
1117
|
-
isExpandable(
|
|
1131
|
+
isExpandable(lhsArt) && isExpandable(rhsArt) &&
|
|
1118
1132
|
['=', '<', '>', '>=', '<=', '!=', '<>'].includes(op) &&
|
|
1119
1133
|
!(isDollarSelfOrProjectionOperand(lhs) || isDollarSelfOrProjectionOperand(rhs))) {
|
|
1120
1134
|
|
|
1121
1135
|
// if path is scalar and no assoc or has no type (@Core.Computed) use original expression
|
|
1122
1136
|
// only do the expansion on (managed) assocs and (items.)elements, array of check in ON cond is done elsewhere
|
|
1123
|
-
const lhspaths = /*isScalarOrNoType(lhs._art) ? [ lhs ] : */ flattenPath({ _art:
|
|
1124
|
-
const rhspaths = /*isScalarOrNoType(rhs._art) ? [ rhs ] : */ flattenPath({ _art:
|
|
1137
|
+
const lhspaths = /*isScalarOrNoType(lhs._art) ? [ lhs ] : */ flattenPath({ _art: lhsArt, ref: lhs.ref }, false, true );
|
|
1138
|
+
const rhspaths = /*isScalarOrNoType(rhs._art) ? [ rhs ] : */ flattenPath({ _art: rhsArt, ref: rhs.ref }, false, true );
|
|
1125
1139
|
|
|
1126
1140
|
// mapping dict for lhs/rhs for mismatch check
|
|
1127
1141
|
// strip lhs/rhs prefix from flattened paths to check remaining common trailing path
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { setProp, forEachGeneric, forEachDefinition, isBetaEnabled } = require('../base/model');
|
|
4
|
-
|
|
4
|
+
const { makeMessageFunction } = require('../base/messages');
|
|
5
5
|
const { recompileX } = require('../compiler/index');
|
|
6
|
-
|
|
6
|
+
const { linkToOrigin, pathName } = require('../compiler/utils');
|
|
7
7
|
const {compactModel, compactExpr} = require('../json/to-csn');
|
|
8
8
|
const { deduplicateMessages } = require('../base/messages');
|
|
9
|
-
const timetrace = require('../utils/timetrace');
|
|
9
|
+
const { timetrace } = require('../utils/timetrace');
|
|
10
10
|
// Paths that start with an artifact of protected kind are special
|
|
11
11
|
// either ignore them in QAT building or in path rewriting
|
|
12
12
|
const internalArtifactKinds = ['builtin'/*, '$parameters'*/, 'param'];
|
|
@@ -179,7 +179,7 @@ function translateAssocsToJoins(model, inputOptions = {})
|
|
|
179
179
|
let joinTree = query.from;
|
|
180
180
|
for(let tan in query.$tableAliases)
|
|
181
181
|
{
|
|
182
|
-
if(
|
|
182
|
+
if(query.$tableAliases[tan].kind !== '$self') // don't drive into $projection/$self tableAlias (yet)
|
|
183
183
|
{
|
|
184
184
|
let ta = query.$tableAliases[tan];
|
|
185
185
|
joinTree = createJoinTree(env, joinTree, ta.$qat, 'left', '$qat', ta.$QA);
|
|
@@ -200,7 +200,7 @@ function translateAssocsToJoins(model, inputOptions = {})
|
|
|
200
200
|
function createQAForFromClauseSubQuery(query, env)
|
|
201
201
|
{
|
|
202
202
|
for (let taName in query.$tableAliases) {
|
|
203
|
-
if (
|
|
203
|
+
if (query.$tableAliases[taName].kind !== '$self') {
|
|
204
204
|
let ta = query.$tableAliases[taName];
|
|
205
205
|
if(!ta.$QA) {
|
|
206
206
|
ta.$QA = createQA(env, ta._origin, taName, undefined);
|
|
@@ -241,14 +241,6 @@ function translateAssocsToJoins(model, inputOptions = {})
|
|
|
241
241
|
{
|
|
242
242
|
art.$QA = createQA(env, art.target._artifact, art.name.id );
|
|
243
243
|
art.$QA.mixin = true;
|
|
244
|
-
/* Mark mixin definition to be _ignored:
|
|
245
|
-
- If the mixin is used, it is now resolved into a join => definition vaporizes
|
|
246
|
-
- If the mixin is published, forHana backend must create a __copy with rewritten
|
|
247
|
-
$projection ON conditon and publish it with alias.
|
|
248
|
-
- If the mixin is neither be used nor published it shall not be visible to the database
|
|
249
|
-
(internal mixin).
|
|
250
|
-
*/
|
|
251
|
-
art.$a2j = { _ignore: true };
|
|
252
244
|
}
|
|
253
245
|
});
|
|
254
246
|
}
|
|
@@ -317,7 +309,7 @@ function translateAssocsToJoins(model, inputOptions = {})
|
|
|
317
309
|
let [QA, ps] = rightMostQA(tail, head._navigation._parent.$QA || head._navigation.$QA);
|
|
318
310
|
if(!QA) {
|
|
319
311
|
error(null, pathNode.$location,
|
|
320
|
-
{ name: pathNode.path
|
|
312
|
+
{ name: pathName(pathNode.path) },
|
|
321
313
|
'Please debug me: No QA found for generic path rewriting in $(NAME)')
|
|
322
314
|
return;
|
|
323
315
|
}
|
|
@@ -1403,7 +1395,7 @@ function translateAssocsToJoins(model, inputOptions = {})
|
|
|
1403
1395
|
|
|
1404
1396
|
let [head, ...tail] = path;
|
|
1405
1397
|
|
|
1406
|
-
if(['$projection', '$self'].includes(head.id) && tail.length) {
|
|
1398
|
+
if(['$projection', '$self'].includes(head.id) && tail.length && head._navigation.kind === '$self') {
|
|
1407
1399
|
// make sure not to truncate tail
|
|
1408
1400
|
if(tail.length > 1)
|
|
1409
1401
|
[head, ...tail] = tail;
|
package/lib/utils/file.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
'use strict';
|
|
4
4
|
|
|
5
5
|
const fs = require('fs');
|
|
6
|
+
const util = require('util');
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Split the given source string into its lines. Respects Unix,
|
|
@@ -19,8 +20,8 @@ function splitLines(src) {
|
|
|
19
20
|
* Returns filesystem utils readFile(), isFile(), realpath() for _CDS_ usage.
|
|
20
21
|
* This includes a trace as well as usage of a file cache.
|
|
21
22
|
*
|
|
22
|
-
* Note: The synchronous versions accept a callback
|
|
23
|
-
* immediately! This is different from NodeJS's readFileSync()!
|
|
23
|
+
* Note: The synchronous versions accept a callback instead of being async (duh!), which
|
|
24
|
+
* is executed immediately! This is different from NodeJS's readFileSync()!
|
|
24
25
|
* This is done to allow using it in places where fs.readFile (async) is used.
|
|
25
26
|
*
|
|
26
27
|
* @param {object} fileCache
|
|
@@ -30,7 +31,7 @@ function cdsFs(fileCache, enableTrace) {
|
|
|
30
31
|
const readFile = _wrapReadFileCached(fs.readFile);
|
|
31
32
|
const readFileSync = _wrapReadFileCached((filename, enc, cb) => {
|
|
32
33
|
try {
|
|
33
|
-
cb(null, fs.readFileSync( filename, enc ));
|
|
34
|
+
cb(null, fs.readFileSync( filename, { encoding: enc } ));
|
|
34
35
|
}
|
|
35
36
|
catch (err) {
|
|
36
37
|
cb(err, null);
|
|
@@ -47,10 +48,13 @@ function cdsFs(fileCache, enableTrace) {
|
|
|
47
48
|
});
|
|
48
49
|
|
|
49
50
|
return {
|
|
51
|
+
readFileAsync: util.promisify(readFile),
|
|
50
52
|
readFile,
|
|
51
53
|
readFileSync,
|
|
54
|
+
isFileAsync: util.promisify(isFile),
|
|
52
55
|
isFile,
|
|
53
56
|
isFileSync,
|
|
57
|
+
realpathAsync: util.promisify(realpath),
|
|
54
58
|
realpath,
|
|
55
59
|
realpathSync,
|
|
56
60
|
};
|
|
@@ -72,7 +76,7 @@ function cdsFs(fileCache, enableTrace) {
|
|
|
72
76
|
* Wraps the given reader into a cached environment including a trace.
|
|
73
77
|
* The given @p reader must have the same signature as fs.readFile.
|
|
74
78
|
*
|
|
75
|
-
* @param {(filename: string, enc
|
|
79
|
+
* @param {(filename: string, enc, cb: (err, data) => void) => void} reader
|
|
76
80
|
*/
|
|
77
81
|
function _wrapReadFileCached( reader ) {
|
|
78
82
|
return (filename, enc, cb) => {
|
|
@@ -93,7 +97,9 @@ function cdsFs(fileCache, enableTrace) {
|
|
|
93
97
|
body.syscall = 'open';
|
|
94
98
|
body.path = filename;
|
|
95
99
|
}
|
|
96
|
-
if (body
|
|
100
|
+
if (body && body.stack && body.message) {
|
|
101
|
+
// NOTE: checks for instanceof Error are not reliable if error
|
|
102
|
+
// created in different execution env
|
|
97
103
|
traceFS( 'READFILE:cache-error:', filename, body.message );
|
|
98
104
|
cb( body ); // no need for process.nextTick( cb, body ) with moduleResolve
|
|
99
105
|
}
|
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.
|
|
6
|
-
//
|
|
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
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
|
|
36
|
+
function term(useColor = 'auto') {
|
|
37
|
+
let hasColor = hasColorShell;
|
|
38
|
+
changeColorMode(useColor);
|
|
51
39
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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 };
|
package/lib/utils/timetrace.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* @class TimeTrace
|
|
7
7
|
*/
|
|
8
|
-
class
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* @param {number} indent
|
|
21
|
+
/**
|
|
22
|
+
* Start watch.
|
|
32
23
|
*/
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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
|
|
87
|
+
const b = new StopWatch(id);
|
|
71
88
|
this.traceStack.push(b);
|
|
72
|
-
b.start(
|
|
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(
|
|
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,58 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* If a mixin association is published, return the mixin association.
|
|
5
|
-
*
|
|
6
|
-
* @param {CSN.Query} query Query of the artifact to check
|
|
7
|
-
* @param {object} association Association (Element) published by the view
|
|
8
|
-
* @param {string} associationName
|
|
9
|
-
* @returns {object} The mixin association
|
|
10
|
-
*/
|
|
11
|
-
function getMixinAssocOfQueryIfPublished(query, association, associationName) {
|
|
12
|
-
if (query && query.SELECT && query.SELECT.mixin) {
|
|
13
|
-
const aliasedColumnsMap = Object.create(null);
|
|
14
|
-
if (query.SELECT.columns) {
|
|
15
|
-
for (const column of query.SELECT.columns) {
|
|
16
|
-
if (column.as && column.ref && column.ref.length === 1)
|
|
17
|
-
aliasedColumnsMap[column.as] = column;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
for (const elem of Object.keys(query.SELECT.mixin)) {
|
|
22
|
-
const mixinElement = query.SELECT.mixin[elem];
|
|
23
|
-
let originalName = associationName;
|
|
24
|
-
if (aliasedColumnsMap[associationName])
|
|
25
|
-
originalName = aliasedColumnsMap[associationName].ref[0];
|
|
26
|
-
|
|
27
|
-
if (elem === originalName)
|
|
28
|
-
return { mixinElement, mixinName: originalName };
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
return {};
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Check wether the given artifact uses the given mixin association.
|
|
36
|
-
*
|
|
37
|
-
* @param {CSN.Query} query Query of the artifact to check
|
|
38
|
-
* @param {object} association Mixin association (Element) to check for
|
|
39
|
-
* @param {string} associationName
|
|
40
|
-
* @returns {boolean} True if used
|
|
41
|
-
*/
|
|
42
|
-
function usesMixinAssociation(query, association, associationName) {
|
|
43
|
-
if (query && query.SELECT && query.SELECT.columns) {
|
|
44
|
-
for (const column of query.SELECT.columns) {
|
|
45
|
-
if (typeof column === 'object' && column.ref && column.ref.length > 1 && (column.ref[0] === associationName || column.ref[0].id === associationName)) {
|
|
46
|
-
// FIXME: This is not necessarily correct: the assoc name needs not be the first component, as e.g. $projection.assoc
|
|
47
|
-
// would be also valid. Check other paths like $self.assoc ....
|
|
48
|
-
return true;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
return false;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
module.exports = {
|
|
56
|
-
usesMixinAssociation,
|
|
57
|
-
getMixinAssocOfQueryIfPublished,
|
|
58
|
-
};
|