@sap/cds-compiler 3.0.0 → 3.1.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 +104 -9
- package/bin/.eslintrc.json +2 -1
- package/bin/cdsc.js +28 -16
- package/doc/API.md +11 -0
- package/doc/CHANGELOG_ARCHIVE.md +1 -1
- package/doc/CHANGELOG_BETA.md +24 -2
- package/doc/CHANGELOG_DEPRECATED.md +21 -1
- package/lib/api/main.js +92 -40
- package/lib/api/options.js +2 -3
- package/lib/base/keywords.js +64 -1
- package/lib/base/message-registry.js +33 -5
- package/lib/base/messages.js +54 -65
- package/lib/base/model.js +2 -0
- package/lib/base/optionProcessorHelper.js +53 -21
- package/lib/checks/actionsFunctions.js +8 -7
- package/lib/checks/selectItems.js +96 -14
- package/lib/checks/types.js +5 -8
- package/lib/checks/validator.js +1 -2
- package/lib/compiler/assert-consistency.js +65 -13
- package/lib/compiler/base.js +6 -4
- package/lib/compiler/builtins.js +93 -4
- package/lib/compiler/checks.js +1 -1
- package/lib/compiler/define.js +28 -23
- package/lib/compiler/extend.js +20 -11
- package/lib/compiler/finalize-parse-cdl.js +5 -9
- package/lib/compiler/index.js +2 -0
- package/lib/compiler/populate.js +37 -32
- package/lib/compiler/propagator.js +11 -6
- package/lib/compiler/resolve.js +15 -19
- package/lib/compiler/shared.js +54 -18
- package/lib/compiler/tweak-assocs.js +5 -11
- package/lib/compiler/utils.js +15 -6
- package/lib/edm/annotations/genericTranslation.js +12 -2
- package/lib/edm/annotations/preprocessAnnotations.js +18 -15
- package/lib/edm/csn2edm.js +18 -17
- package/lib/edm/edm.js +22 -13
- package/lib/edm/edmAnnoPreprocessor.js +349 -0
- package/lib/edm/edmInboundChecks.js +85 -0
- package/lib/edm/edmPreprocessor.js +336 -665
- package/lib/edm/edmUtils.js +86 -45
- package/lib/gen/Dictionary.json +29 -9
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +1 -2
- package/lib/gen/languageLexer.js +3 -0
- package/lib/gen/languageParser.js +4332 -4496
- package/lib/inspect/.eslintrc.json +4 -0
- package/lib/inspect/index.js +14 -0
- package/lib/inspect/inspectModelStatistics.js +81 -0
- package/lib/inspect/inspectPropagation.js +189 -0
- package/lib/inspect/inspectUtils.js +44 -0
- package/lib/json/from-csn.js +19 -20
- package/lib/json/to-csn.js +11 -8
- package/lib/language/genericAntlrParser.js +150 -92
- package/lib/language/language.g4 +47 -74
- package/lib/main.d.ts +1 -0
- package/lib/model/api.js +1 -1
- package/lib/model/csnRefs.js +56 -29
- package/lib/model/csnUtils.js +29 -14
- package/lib/model/revealInternalProperties.js +6 -4
- package/lib/modelCompare/compare.js +3 -0
- package/lib/optionProcessor.js +81 -38
- package/lib/render/toCdl.js +57 -32
- package/lib/render/toHdbcds.js +1 -1
- package/lib/render/toSql.js +31 -11
- package/lib/render/utils/common.js +3 -4
- package/lib/transform/db/associations.js +43 -35
- package/lib/transform/db/cdsPersistence.js +0 -1
- package/lib/transform/db/flattening.js +3 -4
- package/lib/transform/db/transformExists.js +7 -5
- package/lib/transform/draft/db.js +1 -1
- package/lib/transform/forHanaNew.js +11 -2
- package/lib/transform/forOdataNew.js +4 -4
- package/lib/transform/localized.js +15 -11
- package/lib/transform/odata/typesExposure.js +14 -5
- package/lib/utils/file.js +28 -18
- package/lib/utils/moduleResolve.js +0 -1
- package/package.json +3 -4
- package/share/messages/syntax-expected-integer.md +9 -8
- package/lib/checks/unknownMagic.js +0 -41
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// cds-compiler Inspect Module
|
|
2
|
+
// Used by `cdsc inspect` to gather details about the model such as statistics, etc.
|
|
3
|
+
|
|
4
|
+
'use strict';
|
|
5
|
+
|
|
6
|
+
const { inspectModelStatistics } = require('./inspectModelStatistics');
|
|
7
|
+
const { inspectPropagation } = require('./inspectPropagation');
|
|
8
|
+
const { stringRefToPath } = require('./inspectUtils');
|
|
9
|
+
|
|
10
|
+
module.exports = {
|
|
11
|
+
inspectModelStatistics,
|
|
12
|
+
inspectPropagation,
|
|
13
|
+
stringRefToPath,
|
|
14
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { forEach } = require('../utils/objectUtils');
|
|
4
|
+
const { term } = require('../utils/term');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Return a string representation of the inspected results.
|
|
8
|
+
*
|
|
9
|
+
* @param {XSN.Model} xsn
|
|
10
|
+
* @param {CSN.Options} options
|
|
11
|
+
* @returns {string}
|
|
12
|
+
*/
|
|
13
|
+
function inspectModelStatistics(xsn, options) {
|
|
14
|
+
let result = '';
|
|
15
|
+
|
|
16
|
+
// Default color mode is 'auto'
|
|
17
|
+
const color = term(options.color || 'auto');
|
|
18
|
+
|
|
19
|
+
const defCount = countDefinitionKinds(xsn);
|
|
20
|
+
const sources = {
|
|
21
|
+
cdl: Object.keys(xsn.sources).filter(name => xsn.sources[name].$frontend === 'cdl').length,
|
|
22
|
+
csn: Object.keys(xsn.sources).filter(name => xsn.sources[name].$frontend === 'csn').length,
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
result += `cds-compiler model statistics:
|
|
26
|
+
|
|
27
|
+
${ color.underline('files') }: ${ Object.keys(xsn.sources).length }
|
|
28
|
+
cdl sources: ${ sources.cdl }
|
|
29
|
+
csn sources: ${ sources.csn }
|
|
30
|
+
|
|
31
|
+
${ color.underline('definitions') }: ${ defCount.definitions }
|
|
32
|
+
entities: ${ defCount.entity }
|
|
33
|
+
queries: ${ defCount.view }
|
|
34
|
+
aspects: ${ defCount.aspect }
|
|
35
|
+
events: ${ defCount.event }
|
|
36
|
+
types: ${ defCount.type }
|
|
37
|
+
services: ${ defCount.service }
|
|
38
|
+
context: ${ defCount.context }
|
|
39
|
+
actions: ${ defCount.action }
|
|
40
|
+
functions: ${ defCount.function }
|
|
41
|
+
namespaces: ${ defCount.namespace } (explicitly in CDL)
|
|
42
|
+
|
|
43
|
+
${ color.underline('vocabularies') }: ${ Object.keys(xsn.vocabularies || {}).length }
|
|
44
|
+
`;
|
|
45
|
+
return result;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function countDefinitionKinds(xsn) {
|
|
49
|
+
const result = {
|
|
50
|
+
definitions: 0,
|
|
51
|
+
entity: 0,
|
|
52
|
+
action: 0,
|
|
53
|
+
function: 0,
|
|
54
|
+
aspect: 0,
|
|
55
|
+
event: 0,
|
|
56
|
+
type: 0,
|
|
57
|
+
service: 0,
|
|
58
|
+
context: 0,
|
|
59
|
+
namespace: 0,
|
|
60
|
+
// non-kind
|
|
61
|
+
view: 0,
|
|
62
|
+
};
|
|
63
|
+
forEach(xsn.definitions || {}, (name, def) => {
|
|
64
|
+
if (def.builtin)
|
|
65
|
+
return;
|
|
66
|
+
++result.definitions;
|
|
67
|
+
|
|
68
|
+
if (def.query || def.projection)
|
|
69
|
+
++result.view;
|
|
70
|
+
else if (result[def.kind] !== undefined)
|
|
71
|
+
++result[def.kind];
|
|
72
|
+
else
|
|
73
|
+
throw new Error(`Unhandled kind: ${ def.kind } for ${ name }`);
|
|
74
|
+
});
|
|
75
|
+
return result;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
module.exports = {
|
|
80
|
+
inspectModelStatistics,
|
|
81
|
+
};
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { createMessageFunctions } = require('../base/messages');
|
|
4
|
+
const { locationString } = require('../base/location');
|
|
5
|
+
const { findArtifact, stringRefToPath } = require('./inspectUtils');
|
|
6
|
+
const { term } = require('../utils/term');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @param {XSN.Model} xsn
|
|
10
|
+
* @param {CSN.Options} options
|
|
11
|
+
* @param {string} artifactName
|
|
12
|
+
* @returns {string|null}
|
|
13
|
+
*/
|
|
14
|
+
function inspectPropagation(xsn, options, artifactName) {
|
|
15
|
+
const { error } = createMessageFunctions(options, 'inspect', xsn);
|
|
16
|
+
const result = [];
|
|
17
|
+
|
|
18
|
+
// Default color mode is 'auto'
|
|
19
|
+
const color = term(options.color || 'auto');
|
|
20
|
+
|
|
21
|
+
const path = stringRefToPath(artifactName);
|
|
22
|
+
if (!path) {
|
|
23
|
+
error(null, null, { name: artifactName },
|
|
24
|
+
'Artifact $(NAME) is not a valid path; expected format `<def>[:element]`');
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const artifactXsn = findArtifact(xsn, path);
|
|
29
|
+
|
|
30
|
+
if (!artifactXsn) {
|
|
31
|
+
error(null, null, { name: artifactName },
|
|
32
|
+
// eslint-disable-next-line max-len
|
|
33
|
+
'Artifact $(NAME) not found, only top-level artifacts and their elements are supported for now');
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
result.push(color.underline('analyzing propagation for artifact:'));
|
|
37
|
+
result.push(` name: ${ artifactXsn.name.id }`);
|
|
38
|
+
result.push(` kind: ${ artifactXsn.kind }`);
|
|
39
|
+
|
|
40
|
+
if (artifactXsn.$inferred)
|
|
41
|
+
result.push(` inferred: ${ artifactXsn.$inferred }`);
|
|
42
|
+
|
|
43
|
+
result.push('');
|
|
44
|
+
result.push(` ${ color.underline('annotation propagation:') }`);
|
|
45
|
+
result.push(..._indent(_inspectAnnotations(artifactXsn)));
|
|
46
|
+
|
|
47
|
+
result.push('');
|
|
48
|
+
result.push(` ${ color.underline('element propagation:') }`);
|
|
49
|
+
result.push(..._indent(_inspectElements(artifactXsn)));
|
|
50
|
+
|
|
51
|
+
return result.join('\n');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
@param {string[]} lines
|
|
56
|
+
@param {string} indent
|
|
57
|
+
* @returns {string[]}
|
|
58
|
+
*/
|
|
59
|
+
function _indent(lines, indent = ' ') {
|
|
60
|
+
return lines.map(str => `${ indent }${ str }`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @param {XSN.Artifact} artifactXsn
|
|
65
|
+
* @returns {string[]}
|
|
66
|
+
* @private
|
|
67
|
+
*/
|
|
68
|
+
function _inspectAnnotations(artifactXsn) {
|
|
69
|
+
const result = [];
|
|
70
|
+
const annos = Object.keys(artifactXsn).filter(str => str.startsWith('@')).sort();
|
|
71
|
+
|
|
72
|
+
if (annos.length === 0)
|
|
73
|
+
return [ 'no annotations' ];
|
|
74
|
+
|
|
75
|
+
let maxAnnoLength = 30; // chosen arbitrarily, hopefully average
|
|
76
|
+
for (const anno of annos) {
|
|
77
|
+
const annoXsn = artifactXsn[anno];
|
|
78
|
+
const loc = locationString(annoXsn.name.location);
|
|
79
|
+
let origin;
|
|
80
|
+
switch (annoXsn.$priority) {
|
|
81
|
+
case false:
|
|
82
|
+
if (annoXsn.$inferred)
|
|
83
|
+
origin = 'propagation';
|
|
84
|
+
else
|
|
85
|
+
origin = 'direct';
|
|
86
|
+
break;
|
|
87
|
+
|
|
88
|
+
case 'extend':
|
|
89
|
+
case 'annotate':
|
|
90
|
+
origin = annoXsn.$priority;
|
|
91
|
+
break;
|
|
92
|
+
|
|
93
|
+
case undefined:
|
|
94
|
+
if (annoXsn.$inferred === '$generated') {
|
|
95
|
+
origin = 'generated';
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
// fallthrough
|
|
99
|
+
default:
|
|
100
|
+
throw new Error(`inspect anno: Unhandled Case: ${ annoXsn.$priority }`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
maxAnnoLength = Math.max(maxAnnoLength, anno.length);
|
|
104
|
+
|
|
105
|
+
// origin: assume max length 11 of 'propagation'
|
|
106
|
+
// anno: use max length of all annotations till now
|
|
107
|
+
result.push([ origin.padStart(11), anno.padEnd(maxAnnoLength), loc ].join(' | '));
|
|
108
|
+
}
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* @param {XSN.Artifact} artifactXsn
|
|
114
|
+
* @returns {string[]}
|
|
115
|
+
* @private
|
|
116
|
+
*/
|
|
117
|
+
function _inspectElements(artifactXsn) {
|
|
118
|
+
if (!artifactXsn.elements)
|
|
119
|
+
return [ 'does not have elements' ];
|
|
120
|
+
|
|
121
|
+
const result = [];
|
|
122
|
+
const elements = Object.keys(artifactXsn.elements);
|
|
123
|
+
|
|
124
|
+
let maxElemLength = 12;
|
|
125
|
+
|
|
126
|
+
const inferredNiceOutput = {
|
|
127
|
+
'*': 'wildcard',
|
|
128
|
+
'expand-element': 'expanded',
|
|
129
|
+
'expand-param': 'expanded',
|
|
130
|
+
'aspect-composition': 'composition',
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
for (const element of elements) {
|
|
134
|
+
const elementXsn = artifactXsn.elements[element];
|
|
135
|
+
const loc = locationString(_origin(elementXsn).name.location);
|
|
136
|
+
let origin;
|
|
137
|
+
|
|
138
|
+
if (elementXsn.$inferred) {
|
|
139
|
+
// Use nice(r) output for known $inferred
|
|
140
|
+
if (inferredNiceOutput[elementXsn.$inferred])
|
|
141
|
+
origin = inferredNiceOutput[elementXsn.$inferred];
|
|
142
|
+
else
|
|
143
|
+
origin = elementXsn.$inferred;
|
|
144
|
+
}
|
|
145
|
+
else if (!isContainedInParentLocation(elementXsn, artifactXsn)) {
|
|
146
|
+
// just a heuristic
|
|
147
|
+
origin = 'extend';
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
origin = 'direct';
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
maxElemLength = Math.max(maxElemLength, element.length);
|
|
154
|
+
|
|
155
|
+
// origin: assume max length 11 of 'composition'
|
|
156
|
+
// element: assume average length of 30, chosen randomly
|
|
157
|
+
result.push([ origin.padStart(11), element.padEnd(maxElemLength), loc ].join(' | '));
|
|
158
|
+
}
|
|
159
|
+
return result;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function _origin(elementXsn) {
|
|
163
|
+
while (elementXsn._origin)
|
|
164
|
+
elementXsn = elementXsn._origin;
|
|
165
|
+
return elementXsn;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Returns true if `art` is contained in `parent` according to its location.
|
|
170
|
+
*
|
|
171
|
+
* @param art
|
|
172
|
+
* @param parent
|
|
173
|
+
* @returns {boolean}
|
|
174
|
+
*/
|
|
175
|
+
function isContainedInParentLocation(art, parent) {
|
|
176
|
+
const artLoc = art.location;
|
|
177
|
+
const parentLoc = parent.location;
|
|
178
|
+
if (artLoc.file !== parentLoc.file)
|
|
179
|
+
return false;
|
|
180
|
+
if (artLoc.line < parentLoc.line || artLoc.line > parentLoc.endLine)
|
|
181
|
+
return false;
|
|
182
|
+
// Good enough for now
|
|
183
|
+
// TODO: Check columns
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
module.exports = {
|
|
188
|
+
inspectPropagation,
|
|
189
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Reference (string) to path (array) that can be used to identify an artifact
|
|
5
|
+
* @param str
|
|
6
|
+
* @returns {*[]|*}
|
|
7
|
+
*/
|
|
8
|
+
function stringRefToPath(str) {
|
|
9
|
+
// e.g. `ns.service.E:sub.elem.structured`
|
|
10
|
+
const path = str.split(':');
|
|
11
|
+
if (path.length === 1)
|
|
12
|
+
return path;
|
|
13
|
+
if (path.length > 2)
|
|
14
|
+
return null;
|
|
15
|
+
return [ path[0], ...path[1].split('.') ];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @param {XSN.Model} xsn
|
|
20
|
+
* @param {string} path
|
|
21
|
+
* @private
|
|
22
|
+
*/
|
|
23
|
+
function findArtifact(xsn, path) {
|
|
24
|
+
const segments = [ ...path ];
|
|
25
|
+
const topLevelName = segments[0];
|
|
26
|
+
let art = (xsn.definitions && xsn.definitions[topLevelName]) ||
|
|
27
|
+
(xsn.vocabularies && xsn.vocabularies[topLevelName]);
|
|
28
|
+
if (!art)
|
|
29
|
+
return null;
|
|
30
|
+
segments.shift();
|
|
31
|
+
if (segments.length === 0)
|
|
32
|
+
return art;
|
|
33
|
+
while (segments.length && art) {
|
|
34
|
+
const segment = segments.shift();
|
|
35
|
+
art = (art.items?.elements || art.elements)?.[segment];
|
|
36
|
+
}
|
|
37
|
+
return art || null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
module.exports = {
|
|
42
|
+
stringRefToPath,
|
|
43
|
+
findArtifact,
|
|
44
|
+
};
|
package/lib/json/from-csn.js
CHANGED
|
@@ -88,6 +88,7 @@
|
|
|
88
88
|
*/
|
|
89
89
|
|
|
90
90
|
const { dictAdd } = require('../base/dictionaries');
|
|
91
|
+
const { quotedLiteralPatterns } = require('../compiler/builtins');
|
|
91
92
|
|
|
92
93
|
const $location = Symbol.for('cds.$location');
|
|
93
94
|
|
|
@@ -102,6 +103,7 @@ const ourpropsRegex = /^[_$]?[a-zA-Z]+[0-9]*$/;
|
|
|
102
103
|
const typeProperties = [
|
|
103
104
|
// do not include CSN v0.1.0 properties here:
|
|
104
105
|
'target', 'elements', 'enum', 'items',
|
|
106
|
+
'cardinality', // for association publishing in views
|
|
105
107
|
'type', 'length', 'precision', 'scale', 'srid', 'localized', 'notNull',
|
|
106
108
|
'keys', 'on', // only with 'target'
|
|
107
109
|
];
|
|
@@ -227,7 +229,7 @@ const schema = compileSchema( {
|
|
|
227
229
|
dictionaryOf: definition,
|
|
228
230
|
defaultKind: 'action',
|
|
229
231
|
validKinds: [ 'action', 'function' ],
|
|
230
|
-
inKind: [ 'entity', 'annotate', 'extend' ],
|
|
232
|
+
inKind: [ 'entity', 'aspect', 'annotate', 'extend' ],
|
|
231
233
|
},
|
|
232
234
|
params: {
|
|
233
235
|
dictionaryOf: definition,
|
|
@@ -682,15 +684,6 @@ const topLevelSpec = {
|
|
|
682
684
|
schema,
|
|
683
685
|
};
|
|
684
686
|
|
|
685
|
-
const validLiteralsExtra = Object.assign( Object.create(null), {
|
|
686
|
-
// TODO: should we use quotedLiteralPatterns from genericAntlrParser?
|
|
687
|
-
number: 'string',
|
|
688
|
-
x: 'string',
|
|
689
|
-
time: 'string',
|
|
690
|
-
date: 'string',
|
|
691
|
-
timestamp: 'string',
|
|
692
|
-
} );
|
|
693
|
-
|
|
694
687
|
// Module variables, schema compilation, and functors ------------------------
|
|
695
688
|
|
|
696
689
|
/** @type {(id, location, textOrArguments, texts?) => void} */
|
|
@@ -1288,16 +1281,22 @@ function value( val, spec, xsn ) { // for CSN property 'val'
|
|
|
1288
1281
|
return ignore( val );
|
|
1289
1282
|
}
|
|
1290
1283
|
|
|
1291
|
-
function literal(
|
|
1284
|
+
function literal( lit, spec, xsn, csn ) {
|
|
1292
1285
|
// TODO: general: requires other property (here: 'val')
|
|
1293
1286
|
const type = (csn.val == null) ? 'null' : typeof csn.val;
|
|
1294
|
-
if (
|
|
1295
|
-
return
|
|
1296
|
-
if (typeof
|
|
1297
|
-
|
|
1287
|
+
if (lit === type) // also for 'object' which is an error for 'val'
|
|
1288
|
+
return lit;
|
|
1289
|
+
if (typeof lit === 'string' && quotedLiteralPatterns[lit]?.json_type === type) {
|
|
1290
|
+
const p = quotedLiteralPatterns[lit];
|
|
1291
|
+
if (p && p.test_fn && !p.test_fn(csn.val))
|
|
1292
|
+
warning( 'syntax-invalid-literal', location(), { '#': p.test_variant } );
|
|
1293
|
+
return lit;
|
|
1294
|
+
}
|
|
1295
|
+
if (lit === 'number' && type === 'string') // special case, not a quoted literal in CDL
|
|
1296
|
+
return lit;
|
|
1298
1297
|
error( 'syntax-expected-valid', location(true), { prop: spec.msgProp },
|
|
1299
1298
|
'Expected valid string for property $(PROP)' );
|
|
1300
|
-
return ignore(
|
|
1299
|
+
return ignore( lit );
|
|
1301
1300
|
}
|
|
1302
1301
|
|
|
1303
1302
|
function func( val, spec, xsn ) {
|
|
@@ -1535,7 +1534,7 @@ function getSpec( parentSpec, csn, prop, xor, expected, kind ) {
|
|
|
1535
1534
|
const zero = s.vZeroFor;
|
|
1536
1535
|
if (zero) { // (potential) CSN v0.1.0 property
|
|
1537
1536
|
const group = s.xorGroup;
|
|
1538
|
-
if (
|
|
1537
|
+
if (expected( zero, schema[zero] ) && !(group && xor[group])) {
|
|
1539
1538
|
replaceZeroProp( prop, zero );
|
|
1540
1539
|
if (group)
|
|
1541
1540
|
xor[group] = prop;
|
|
@@ -1555,7 +1554,7 @@ function getSpec( parentSpec, csn, prop, xor, expected, kind ) {
|
|
|
1555
1554
|
std: 'CSN property $(PROP) is not expected in $(OTHERPROP)',
|
|
1556
1555
|
top: 'CSN property $(PROP) is not expected top-level',
|
|
1557
1556
|
def: 'CSN property $(PROP) is not expected by a definition of kind $(KIND)',
|
|
1558
|
-
extend: 'CSN property $(PROP) is not expected by an extend in $(OTHERPROP)
|
|
1557
|
+
extend: 'CSN property $(PROP) is not expected by an extend in $(OTHERPROP)',
|
|
1559
1558
|
annotate: 'CSN property $(PROP) is not expected by an annotate in $(OTHERPROP)',
|
|
1560
1559
|
} );
|
|
1561
1560
|
// TODO: or still augment it? (but then also handle xorGroup)
|
|
@@ -1783,7 +1782,7 @@ function toXsn( csn, filename, options, messageFunctions ) {
|
|
|
1783
1782
|
}
|
|
1784
1783
|
|
|
1785
1784
|
|
|
1786
|
-
function augment( csn, filename = 'csn.json', options = {}, messageFunctions ) {
|
|
1785
|
+
function augment( csn, filename = 'csn.json', options = {}, messageFunctions = {} ) {
|
|
1787
1786
|
try {
|
|
1788
1787
|
return toXsn( csn, filename, options, messageFunctions );
|
|
1789
1788
|
}
|
|
@@ -1793,7 +1792,7 @@ function augment( csn, filename = 'csn.json', options = {}, messageFunctions ) {
|
|
|
1793
1792
|
}
|
|
1794
1793
|
}
|
|
1795
1794
|
|
|
1796
|
-
function parse( source, filename = 'csn.json', options = {}, messageFunctions ) {
|
|
1795
|
+
function parse( source, filename = 'csn.json', options = {}, messageFunctions = {} ) {
|
|
1797
1796
|
try {
|
|
1798
1797
|
return augment( JSON.parse(source), filename, options, messageFunctions );
|
|
1799
1798
|
}
|
package/lib/json/to-csn.js
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
const { locationString } = require('../base/messages');
|
|
15
15
|
const { isBetaEnabled, isDeprecatedEnabled } = require('../base/model');
|
|
16
|
+
const { pathName } = require('../compiler/utils');
|
|
16
17
|
|
|
17
18
|
const compilerVersion = require('../../package.json').version;
|
|
18
19
|
const creator = `CDS Compiler v${ compilerVersion }`;
|
|
@@ -126,9 +127,6 @@ const transformers = {
|
|
|
126
127
|
// location is not renamed to $location as the name is well established in
|
|
127
128
|
// XSN and too many places (also outside the compiler) had to be adapted
|
|
128
129
|
location, // non-enumerable $location in CSN
|
|
129
|
-
$a2j: (e, csn) => { // on artifact level
|
|
130
|
-
Object.assign( csn, e );
|
|
131
|
-
},
|
|
132
130
|
$extra: (e, csn) => {
|
|
133
131
|
Object.assign( csn, e );
|
|
134
132
|
},
|
|
@@ -184,9 +182,11 @@ const propertyOrder = (function orderPositions() {
|
|
|
184
182
|
}());
|
|
185
183
|
|
|
186
184
|
// sync with definition in from-csn.js:
|
|
185
|
+
// Note: Order here is also the property order in CSN.
|
|
187
186
|
const typeProperties = [
|
|
188
|
-
'target', 'elements', 'enum', 'items',
|
|
189
|
-
'
|
|
187
|
+
'target', 'elements', 'enum', 'items',
|
|
188
|
+
'cardinality', // for association publishing in views
|
|
189
|
+
'type', 'length', 'precision', 'scale', 'srid', 'localized', // TODO: notNull?
|
|
190
190
|
'foreignKeys', 'on', // for explicit ON/keys with REDIRECTED
|
|
191
191
|
];
|
|
192
192
|
|
|
@@ -1218,8 +1218,8 @@ function value( node ) {
|
|
|
1218
1218
|
if (node.$inferred && gensrcFlavor)
|
|
1219
1219
|
return undefined;
|
|
1220
1220
|
if (node.path) {
|
|
1221
|
-
const ref = node.path
|
|
1222
|
-
return extra( { '=': node.variant ? `${ ref }#${ node.variant.
|
|
1221
|
+
const ref = pathName( node.path );
|
|
1222
|
+
return extra( { '=': node.variant ? `${ ref }#${ pathName(node.variant.path) }` : ref }, node );
|
|
1223
1223
|
}
|
|
1224
1224
|
if (node.literal === 'enum')
|
|
1225
1225
|
return extra( { '#': node.sym.id }, node );
|
|
@@ -1275,8 +1275,11 @@ function expression( node, dollarExtra ) {
|
|
|
1275
1275
|
return { ref: [ node.param.val ], param: true }; // CDL rule for runtimes
|
|
1276
1276
|
}
|
|
1277
1277
|
if (node.path) {
|
|
1278
|
+
const ref = node.path.map( pathItem );
|
|
1279
|
+
if (node.path.$prefix)
|
|
1280
|
+
ref.unshift( node.path.$prefix );
|
|
1278
1281
|
// we would need to consider node.global here if we introduce that
|
|
1279
|
-
return extra( { ref
|
|
1282
|
+
return extra( { ref }, dollarExtraNode );
|
|
1280
1283
|
}
|
|
1281
1284
|
if (node.literal) {
|
|
1282
1285
|
if (typeof node.val === node.literal || node.val === null)
|