@sap/cds-compiler 3.1.0 → 3.3.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 +90 -3
- package/bin/cdsc.js +1 -1
- package/doc/CHANGELOG_BETA.md +18 -0
- package/lib/api/main.js +8 -13
- package/lib/base/error.js +2 -2
- package/lib/base/keywords.js +2 -24
- package/lib/base/message-registry.js +43 -14
- package/lib/base/messages.js +20 -10
- package/lib/base/model.js +1 -1
- package/lib/checks/actionsFunctions.js +1 -1
- package/lib/checks/annotationsOData.js +2 -2
- package/lib/checks/arrayOfs.js +15 -7
- package/lib/checks/cdsPersistence.js +1 -1
- package/lib/checks/checkForTypes.js +48 -0
- package/lib/checks/defaultValues.js +2 -2
- package/lib/checks/elements.js +81 -6
- package/lib/checks/foreignKeys.js +12 -13
- package/lib/checks/invalidTarget.js +10 -11
- package/lib/checks/managedInType.js +21 -15
- package/lib/checks/nullableKeys.js +1 -1
- package/lib/checks/onConditions.js +9 -9
- package/lib/checks/parameters.js +21 -0
- package/lib/checks/selectItems.js +1 -1
- package/lib/checks/types.js +2 -2
- package/lib/checks/utils.js +17 -7
- package/lib/checks/validator.js +26 -14
- package/lib/compiler/assert-consistency.js +13 -6
- package/lib/compiler/builtins.js +8 -0
- package/lib/compiler/checks.js +40 -33
- package/lib/compiler/define.js +50 -44
- package/lib/compiler/extend.js +303 -37
- package/lib/compiler/kick-start.js +2 -35
- package/lib/compiler/populate.js +83 -62
- package/lib/compiler/propagator.js +1 -1
- package/lib/compiler/resolve.js +61 -104
- package/lib/compiler/shared.js +16 -6
- package/lib/compiler/tweak-assocs.js +25 -12
- package/lib/compiler/utils.js +2 -2
- package/lib/edm/annotations/genericTranslation.js +15 -5
- package/lib/edm/csn2edm.js +10 -10
- package/lib/edm/edm.js +17 -9
- package/lib/edm/edmPreprocessor.js +82 -42
- package/lib/edm/edmUtils.js +18 -16
- package/lib/gen/Dictionary.json +14 -0
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +3 -2
- package/lib/gen/languageParser.js +4205 -4100
- package/lib/inspect/inspectModelStatistics.js +1 -1
- package/lib/inspect/inspectPropagation.js +23 -9
- package/lib/json/csnVersion.js +1 -1
- package/lib/json/from-csn.js +26 -19
- package/lib/json/to-csn.js +47 -5
- package/lib/language/antlrParser.js +1 -1
- package/lib/language/genericAntlrParser.js +29 -13
- package/lib/language/language.g4 +28 -8
- package/lib/main.d.ts +3 -6
- package/lib/model/.eslintrc.json +13 -0
- package/lib/model/api.js +4 -2
- package/lib/model/csnRefs.js +74 -47
- package/lib/model/csnUtils.js +236 -218
- package/lib/model/enrichCsn.js +41 -31
- package/lib/model/revealInternalProperties.js +61 -57
- package/lib/model/sortViews.js +31 -31
- package/lib/modelCompare/compare.js +6 -6
- package/lib/optionProcessor.js +5 -0
- package/lib/render/manageConstraints.js +2 -2
- package/lib/render/toCdl.js +31 -44
- package/lib/render/toHdbcds.js +7 -5
- package/lib/render/toRename.js +4 -4
- package/lib/render/toSql.js +11 -5
- package/lib/render/utils/common.js +20 -9
- package/lib/render/utils/sql.js +5 -5
- package/lib/transform/db/applyTransformations.js +32 -3
- package/lib/transform/db/expansion.js +81 -37
- package/lib/transform/db/flattening.js +1 -1
- package/lib/transform/db/temporal.js +1 -1
- package/lib/transform/db/transformExists.js +1 -1
- package/lib/transform/forOdataNew.js +10 -7
- package/lib/transform/{forHanaNew.js → forRelationalDB.js} +7 -7
- package/lib/transform/localized.js +28 -19
- package/lib/transform/odata/toFinalBaseType.js +8 -11
- package/lib/transform/odata/typesExposure.js +1 -1
- package/lib/transform/transformUtilsNew.js +101 -39
- package/lib/transform/translateAssocsToJoins.js +5 -4
- package/lib/utils/moduleResolve.js +5 -5
- package/lib/utils/objectUtils.js +3 -3
- package/package.json +2 -2
- package/share/messages/anno-duplicate-unrelated-layer.md +6 -6
- package/share/messages/check-proper-type-of.md +4 -4
- package/share/messages/check-proper-type.md +2 -2
- package/share/messages/duplicate-autoexposed.md +4 -4
- package/share/messages/extend-repeated-intralayer.md +4 -5
- package/share/messages/extend-unrelated-layer.md +4 -4
- package/share/messages/message-explanations.json +3 -1
- package/share/messages/redirected-to-ambiguous.md +7 -6
- package/share/messages/redirected-to-complex.md +63 -0
- package/share/messages/redirected-to-unrelated.md +6 -5
- package/share/messages/rewrite-not-supported.md +4 -4
- package/share/messages/syntax-expected-integer.md +3 -3
- package/share/messages/wildcard-excluding-one.md +37 -0
|
@@ -14,7 +14,7 @@ function inspectModelStatistics(xsn, options) {
|
|
|
14
14
|
let result = '';
|
|
15
15
|
|
|
16
16
|
// Default color mode is 'auto'
|
|
17
|
-
const color = term(options.color
|
|
17
|
+
const color = term(options.color !== undefined ? options.color : 'auto');
|
|
18
18
|
|
|
19
19
|
const defCount = countDefinitionKinds(xsn);
|
|
20
20
|
const sources = {
|
|
@@ -16,7 +16,7 @@ function inspectPropagation(xsn, options, artifactName) {
|
|
|
16
16
|
const result = [];
|
|
17
17
|
|
|
18
18
|
// Default color mode is 'auto'
|
|
19
|
-
const color = term(options.color
|
|
19
|
+
const color = term(options.color !== undefined ? options.color : 'auto');
|
|
20
20
|
|
|
21
21
|
const path = stringRefToPath(artifactName);
|
|
22
22
|
if (!path) {
|
|
@@ -121,19 +121,28 @@ function _inspectElements(artifactXsn) {
|
|
|
121
121
|
const result = [];
|
|
122
122
|
const elements = Object.keys(artifactXsn.elements);
|
|
123
123
|
|
|
124
|
-
let maxElemLength = 12;
|
|
125
|
-
|
|
126
124
|
const inferredNiceOutput = {
|
|
127
125
|
'*': 'wildcard',
|
|
128
|
-
'expand-element': 'expanded',
|
|
129
|
-
'expand-param': 'expanded',
|
|
130
126
|
'aspect-composition': 'composition',
|
|
131
127
|
};
|
|
132
128
|
|
|
129
|
+
let maxElemLength = 12;
|
|
130
|
+
let maxOriginLength = 6;
|
|
131
|
+
|
|
132
|
+
// type: assume max length 11 of 'composition'
|
|
133
|
+
// element: assume average length of 30, chosen randomly
|
|
134
|
+
result.push([
|
|
135
|
+
'type'.padStart(11),
|
|
136
|
+
'element'.padEnd(maxElemLength),
|
|
137
|
+
'origin'.padEnd(maxOriginLength),
|
|
138
|
+
'location (definition)',
|
|
139
|
+
].join(' | '));
|
|
140
|
+
|
|
133
141
|
for (const element of elements) {
|
|
134
142
|
const elementXsn = artifactXsn.elements[element];
|
|
135
143
|
const loc = locationString(_origin(elementXsn).name.location);
|
|
136
144
|
let origin;
|
|
145
|
+
const originName = elementXsn._origin?.name?.absolute || '';
|
|
137
146
|
|
|
138
147
|
if (elementXsn.$inferred) {
|
|
139
148
|
// Use nice(r) output for known $inferred
|
|
@@ -151,11 +160,16 @@ function _inspectElements(artifactXsn) {
|
|
|
151
160
|
}
|
|
152
161
|
|
|
153
162
|
maxElemLength = Math.max(maxElemLength, element.length);
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
163
|
+
maxOriginLength = Math.max(maxOriginLength, originName.length);
|
|
164
|
+
|
|
165
|
+
result.push([
|
|
166
|
+
origin.padStart(11),
|
|
167
|
+
element.padEnd(maxElemLength),
|
|
168
|
+
originName.padEnd(maxOriginLength),
|
|
169
|
+
loc,
|
|
170
|
+
].join(' | '));
|
|
158
171
|
}
|
|
172
|
+
|
|
159
173
|
return result;
|
|
160
174
|
}
|
|
161
175
|
|
package/lib/json/csnVersion.js
CHANGED
|
@@ -39,7 +39,7 @@ function checkCSNVersion(csn, options) {
|
|
|
39
39
|
errStr += `${ csn.version && csn.version.csn ? csn.version.csn : (csn.$version ? csn.$version : 'not available') }"`;
|
|
40
40
|
errStr += (options.newCsn !== undefined) ? `, options.newCsn: ${ options.newCsn }` : '';
|
|
41
41
|
|
|
42
|
-
error(null, null, errStr);
|
|
42
|
+
error(null, null, {}, errStr);
|
|
43
43
|
throwWithAnyError();
|
|
44
44
|
}
|
|
45
45
|
}
|
package/lib/json/from-csn.js
CHANGED
|
@@ -117,13 +117,14 @@ const exprProperties = [
|
|
|
117
117
|
const xorGroups = {
|
|
118
118
|
// include CSN v0.1.0 properties here:
|
|
119
119
|
':type': [ 'target', 'elements', 'enum', 'items' ],
|
|
120
|
-
':expr': [
|
|
121
|
-
'ref', 'xpr', 'list', 'val', '#', 'func', 'SELECT', 'SET',
|
|
120
|
+
':expr': [ // see also xorException property in schema
|
|
121
|
+
'ref', 'xpr', 'list', 'val', '#', 'func', 'SELECT', 'SET', 'expand',
|
|
122
122
|
'=', 'path', 'value', 'op', // '='/'path' is CSN v0.1.0 here
|
|
123
123
|
],
|
|
124
124
|
':ext': [ 'annotate', 'extend' ], // TODO: better msg for test/negative/UnexpectedProperties.csn
|
|
125
125
|
':assoc': [ 'on', 'keys', 'foreignKeys', 'onCond' ], // 'foreignKeys'/'onCond' is CSN v0.1.0
|
|
126
|
-
|
|
126
|
+
// TODO - improve consequential errors: assume no name given with `join` or `inline`?
|
|
127
|
+
as: [ 'as', 'join', 'inline' ],
|
|
127
128
|
scope: [ 'param', 'global' ],
|
|
128
129
|
quantifier: [ 'some', 'any', 'distinct', 'all' ],
|
|
129
130
|
// quantifiers 'some' and 'any are 'xpr' token strings in CSN v1.0
|
|
@@ -155,11 +156,12 @@ const schemaClasses = {
|
|
|
155
156
|
defaultKind: '$column',
|
|
156
157
|
validKinds: [], // pseudo kind '$column'
|
|
157
158
|
// A column with only as+cast.type is a new association
|
|
158
|
-
requires: [ 'ref', '
|
|
159
|
+
requires: [ 'ref', 'cast', 'xpr', 'val', '#', 'func', 'list', 'SELECT', 'SET', 'expand' ],
|
|
159
160
|
schema: {
|
|
160
161
|
xpr: {
|
|
161
162
|
class: 'condition',
|
|
162
163
|
type: xprInValue,
|
|
164
|
+
xorException: 'func', // see xorGroup :expr
|
|
163
165
|
inKind: [ '$column' ],
|
|
164
166
|
inValue: true,
|
|
165
167
|
},
|
|
@@ -248,10 +250,12 @@ const schema = compileSchema( {
|
|
|
248
250
|
},
|
|
249
251
|
expand: {
|
|
250
252
|
class: 'columns',
|
|
251
|
-
|
|
253
|
+
xorException: 'ref', // see xorGroup :expr
|
|
254
|
+
inKind: [ '$column' ], // only valid in $column
|
|
252
255
|
},
|
|
253
256
|
inline: {
|
|
254
257
|
class: 'columns',
|
|
258
|
+
onlyWith: 'ref',
|
|
255
259
|
inKind: [ '$column' ], // only valid in $column
|
|
256
260
|
},
|
|
257
261
|
keys: {
|
|
@@ -294,7 +298,7 @@ const schema = compileSchema( {
|
|
|
294
298
|
type: artifactRef,
|
|
295
299
|
msgId: 'syntax-expected-reference',
|
|
296
300
|
optional: [ 'ref', 'global' ],
|
|
297
|
-
inKind: [ 'element', 'type', 'param', 'mixin', 'event', 'annotation' ],
|
|
301
|
+
inKind: [ 'element', 'type', 'param', 'mixin', 'event', 'annotation', 'extend' ],
|
|
298
302
|
},
|
|
299
303
|
targetAspect: {
|
|
300
304
|
type: artifactRef,
|
|
@@ -323,20 +327,20 @@ const schema = compileSchema( {
|
|
|
323
327
|
},
|
|
324
328
|
length: {
|
|
325
329
|
type: natnum,
|
|
326
|
-
inKind: [ 'element', 'type', 'param', 'annotation' ],
|
|
330
|
+
inKind: [ 'element', 'type', 'param', 'annotation', 'extend' ],
|
|
327
331
|
// we do not require a 'type', too - could be useful alone in a 'cast'
|
|
328
332
|
},
|
|
329
333
|
precision: {
|
|
330
334
|
type: natnum,
|
|
331
|
-
inKind: [ 'element', 'type', 'param', 'annotation' ],
|
|
335
|
+
inKind: [ 'element', 'type', 'param', 'annotation', 'extend' ],
|
|
332
336
|
},
|
|
333
337
|
scale: {
|
|
334
338
|
type: scalenum,
|
|
335
|
-
inKind: [ 'element', 'type', 'param', 'annotation' ],
|
|
339
|
+
inKind: [ 'element', 'type', 'param', 'annotation', 'extend' ],
|
|
336
340
|
},
|
|
337
341
|
srid: {
|
|
338
342
|
type: natnum,
|
|
339
|
-
inKind: [ 'element', 'type', 'param', 'annotation' ],
|
|
343
|
+
inKind: [ 'element', 'type', 'param', 'annotation' ], // no 'extend'!
|
|
340
344
|
},
|
|
341
345
|
srcmin: { // in 'cardinality'
|
|
342
346
|
type: renameTo( 'sourceMin', natnum ),
|
|
@@ -372,6 +376,7 @@ const schema = compileSchema( {
|
|
|
372
376
|
minLength: 1,
|
|
373
377
|
requires: 'id',
|
|
374
378
|
optional: [ 'id', 'args', 'cardinality', 'where' ],
|
|
379
|
+
xorException: 'expand', // see xorGroup :expr
|
|
375
380
|
inKind: [ '$column', 'key' ],
|
|
376
381
|
},
|
|
377
382
|
id: { // in 'ref' item
|
|
@@ -389,6 +394,7 @@ const schema = compileSchema( {
|
|
|
389
394
|
},
|
|
390
395
|
func: {
|
|
391
396
|
type: func,
|
|
397
|
+
xorException: 'xpr', // see xorGroup :expr
|
|
392
398
|
inKind: [ '$column' ],
|
|
393
399
|
},
|
|
394
400
|
args: {
|
|
@@ -405,6 +411,7 @@ const schema = compileSchema( {
|
|
|
405
411
|
xpr: {
|
|
406
412
|
class: 'condition',
|
|
407
413
|
type: xpr,
|
|
414
|
+
xorException: 'func', // see xorGroup :expr
|
|
408
415
|
// special treatment in $column
|
|
409
416
|
},
|
|
410
417
|
list: {
|
|
@@ -747,6 +754,7 @@ function compileSchema( specs, proto = null) {
|
|
|
747
754
|
}
|
|
748
755
|
if (proto)
|
|
749
756
|
return r;
|
|
757
|
+
// Set property 'inValue' in main schema only:
|
|
750
758
|
for (const prop of exprProperties) {
|
|
751
759
|
if (r[prop].inValue === undefined)
|
|
752
760
|
r[prop].inValue = true;
|
|
@@ -1559,7 +1567,7 @@ function getSpec( parentSpec, csn, prop, xor, expected, kind ) {
|
|
|
1559
1567
|
} );
|
|
1560
1568
|
// TODO: or still augment it? (but then also handle xorGroup)
|
|
1561
1569
|
}
|
|
1562
|
-
else if (checkAndSetXorGroup( s.xorGroup, prop, xor )) {
|
|
1570
|
+
else if (checkAndSetXorGroup( s.xorGroup, s.xorException, prop, xor )) {
|
|
1563
1571
|
onlyWith( s, s.onlyWith, csn, prop, xor, expected );
|
|
1564
1572
|
return s;
|
|
1565
1573
|
}
|
|
@@ -1622,18 +1630,17 @@ function onlyWith( spec, need, csn, prop, xor, expected ) {
|
|
|
1622
1630
|
return spec;
|
|
1623
1631
|
}
|
|
1624
1632
|
|
|
1625
|
-
function checkAndSetXorGroup( group, prop, xor ) {
|
|
1633
|
+
function checkAndSetXorGroup( group, exception, prop, xor ) {
|
|
1626
1634
|
if (!group)
|
|
1627
1635
|
return true;
|
|
1628
|
-
|
|
1636
|
+
const otherprop = xor[group];
|
|
1637
|
+
if (!otherprop) {
|
|
1629
1638
|
xor[group] = prop;
|
|
1630
1639
|
return true;
|
|
1631
1640
|
}
|
|
1632
|
-
if (
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
error( 'syntax-excluded-property', location(true),
|
|
1636
|
-
{ prop, otherprop: xor[group] },
|
|
1641
|
+
if (otherprop === exception)
|
|
1642
|
+
return true;
|
|
1643
|
+
error( 'syntax-excluded-property', location(true), { prop, otherprop },
|
|
1637
1644
|
'CSN property $(PROP) can only be used alternatively to $(OTHERPROP)');
|
|
1638
1645
|
return false;
|
|
1639
1646
|
}
|
|
@@ -1767,7 +1774,7 @@ function toXsn( csn, filename, options, messageFunctions ) {
|
|
|
1767
1774
|
({ message, error, warning, info } = messageFunctions);
|
|
1768
1775
|
|
|
1769
1776
|
if (csnVersionZero) {
|
|
1770
|
-
warning( 'syntax-csn-zero-version', location(true),
|
|
1777
|
+
warning( 'syntax-csn-zero-version', location(true), {},
|
|
1771
1778
|
'Parsing CSN version 0.1.0' );
|
|
1772
1779
|
}
|
|
1773
1780
|
const r = object( csn, topLevelSpec );
|
package/lib/json/to-csn.js
CHANGED
|
@@ -252,9 +252,10 @@ function sortCsn( csn, cloneOptions = false ) {
|
|
|
252
252
|
const sortDict = n === 'definitions' &&
|
|
253
253
|
(!cloneOptions || cloneOptions.testMode || cloneOptions.testSortCsn);
|
|
254
254
|
const val = csn[n];
|
|
255
|
-
if (!val || typeof val !== 'object' ||
|
|
255
|
+
if (!val || typeof val !== 'object' || csnDirectValues.includes(n))
|
|
256
256
|
r[n] = val;
|
|
257
|
-
|
|
257
|
+
else if (n.charAt(0) === '@')
|
|
258
|
+
r[n] = cloneAnnotationValue( val );
|
|
258
259
|
else if (csnDictionaries.includes(n) && !Array.isArray(val))
|
|
259
260
|
// Array check for property `args` which may either be a dictionary or an array.
|
|
260
261
|
r[n] = csnDictionary( val, sortDict, cloneOptions );
|
|
@@ -279,6 +280,12 @@ function sortCsn( csn, cloneOptions = false ) {
|
|
|
279
280
|
return r;
|
|
280
281
|
}
|
|
281
282
|
|
|
283
|
+
function cloneAnnotationValue(val) {
|
|
284
|
+
if (typeof val !== 'object') // scalar
|
|
285
|
+
return val;
|
|
286
|
+
return JSON.parse( JSON.stringify( val ) );
|
|
287
|
+
}
|
|
288
|
+
|
|
282
289
|
/**
|
|
283
290
|
* Check whether the given object has non enumerable property.
|
|
284
291
|
* Ensure that we don't take it from the prototype, only "directly" - we accidentally
|
|
@@ -663,7 +670,9 @@ function elements( dict, csn, node ) {
|
|
|
663
670
|
// no 'elements' with SELECT or inferred elements with gensrc;
|
|
664
671
|
// hidden or visible 'elements' will be set in query()
|
|
665
672
|
return undefined;
|
|
666
|
-
|
|
673
|
+
if (dict !== 0)
|
|
674
|
+
return insertOrderDict( dict );
|
|
675
|
+
return undefined;
|
|
667
676
|
}
|
|
668
677
|
|
|
669
678
|
function enumDict( dict, csn, node ) {
|
|
@@ -927,6 +936,11 @@ function addOrigin( csn, xsn, node ) {
|
|
|
927
936
|
let origin = getOrigin( node );
|
|
928
937
|
if (xsn.$inferred === 'composition-entity') {
|
|
929
938
|
csn.$origin = originRef( origin, xsn );
|
|
939
|
+
inferredPropertiesForOrigin( csn, node );
|
|
940
|
+
return;
|
|
941
|
+
}
|
|
942
|
+
else if (xsn.$inferred === 'localized-entity') {
|
|
943
|
+
inferredPropertiesForOrigin( csn, node );
|
|
930
944
|
return;
|
|
931
945
|
}
|
|
932
946
|
else if (!isMember( xsn ) || xsn.kind === 'select') {
|
|
@@ -993,6 +1007,30 @@ function addOrigin( csn, xsn, node ) {
|
|
|
993
1007
|
}
|
|
994
1008
|
}
|
|
995
1009
|
|
|
1010
|
+
/**
|
|
1011
|
+
* Copy properties with $inferred === 'parent-origin' to $origin.
|
|
1012
|
+
* This indicates that the property is neither direct nor can be inferred through $origin.
|
|
1013
|
+
*
|
|
1014
|
+
* @param csn
|
|
1015
|
+
* @param node
|
|
1016
|
+
*/
|
|
1017
|
+
function inferredPropertiesForOrigin( csn, node ) {
|
|
1018
|
+
let hasProp = false;
|
|
1019
|
+
const props = {};
|
|
1020
|
+
for (const prop of Object.keys(node)) {
|
|
1021
|
+
if (node[prop]?.$inferred === 'parent-origin') {
|
|
1022
|
+
hasProp = true;
|
|
1023
|
+
props[prop] = value({ ...node[prop], $inferred: false });
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
const origin = csn.$origin;
|
|
1027
|
+
if (hasProp) {
|
|
1028
|
+
csn.$origin = props;
|
|
1029
|
+
if (origin)
|
|
1030
|
+
csn.$origin.$origin = origin;
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
|
|
996
1034
|
function getParent( art ) {
|
|
997
1035
|
const parent = art._parent;
|
|
998
1036
|
const main = parent._main;
|
|
@@ -1092,7 +1130,9 @@ function type( node, csn, xsn ) {
|
|
|
1092
1130
|
return undefined;
|
|
1093
1131
|
if (xsn._origin) {
|
|
1094
1132
|
if (xsn._origin.$inferred === 'REDIRECTED') { // auto-redirected user-provided target
|
|
1095
|
-
|
|
1133
|
+
const $origin = definition( xsn._origin );
|
|
1134
|
+
if ($origin) // if not rendered as column
|
|
1135
|
+
csn.$origin = $origin;
|
|
1096
1136
|
}
|
|
1097
1137
|
}
|
|
1098
1138
|
return artifactRef( node, !node.$extra );
|
|
@@ -1210,7 +1250,8 @@ function value( node ) {
|
|
|
1210
1250
|
if (!node)
|
|
1211
1251
|
return true; // `@aBool` short for `@aBool: true`
|
|
1212
1252
|
if (universalCsn && node.$inferred) {
|
|
1213
|
-
if (node.$inferred === 'prop' || node.$inferred === '$generated'
|
|
1253
|
+
if (node.$inferred === 'prop' || node.$inferred === '$generated' || // via propagator.js
|
|
1254
|
+
node.$inferred === 'parent-origin')
|
|
1214
1255
|
return undefined;
|
|
1215
1256
|
else if (node.$inferred === 'NULL')
|
|
1216
1257
|
return null;
|
|
@@ -1610,6 +1651,7 @@ function initModuleVars( options = { csnFlavor: 'gensrc' } ) {
|
|
|
1610
1651
|
|
|
1611
1652
|
module.exports = {
|
|
1612
1653
|
cloneCsnDictionary: (csn, options) => csnDictionary(csn, false, options),
|
|
1654
|
+
cloneAnnotationValue,
|
|
1613
1655
|
compactModel,
|
|
1614
1656
|
compactQuery,
|
|
1615
1657
|
compactExpr,
|
|
@@ -25,7 +25,7 @@ class ErrorListener extends antlr4.error.ErrorListener {
|
|
|
25
25
|
// method which is called by generated parser with --trace-parser[-amg]:
|
|
26
26
|
syntaxError( recognizer, offendingSymbol, line, column, msg, e ) {
|
|
27
27
|
if (!(e instanceof CompileMessage)) // not already reported
|
|
28
|
-
recognizer.error( null, offendingSymbol, msg );
|
|
28
|
+
recognizer.error( null, offendingSymbol, {}, msg );
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
|
|
@@ -133,7 +133,7 @@ function notSupportedYet( text, ...tokens ) {
|
|
|
133
133
|
tokens = [ text, ...tokens ];
|
|
134
134
|
text = `${ tokens.map( t => t.text.toUpperCase() ).join(' ') } is not supported`;
|
|
135
135
|
}
|
|
136
|
-
this.error( null, this.tokenLocation( tokens[0], tokens[tokens.length - 1] ), text );
|
|
136
|
+
this.error( null, this.tokenLocation( tokens[0], tokens[tokens.length - 1] ), {}, text );
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
// Use the following function for language constructs which we (currently) do
|
|
@@ -146,7 +146,7 @@ function csnParseOnly( text, ...tokens ) {
|
|
|
146
146
|
tokens = [ text, ...tokens ];
|
|
147
147
|
text = `${ tokens.map( t => t.text.toUpperCase() ).join(' ') } is not supported`;
|
|
148
148
|
}
|
|
149
|
-
this.error( null, this.tokenLocation( tokens[0], tokens[tokens.length - 1] ), text );
|
|
149
|
+
this.error( null, this.tokenLocation( tokens[0], tokens[tokens.length - 1] ), {}, text );
|
|
150
150
|
}
|
|
151
151
|
|
|
152
152
|
/** @this {object} */
|
|
@@ -607,6 +607,8 @@ function classifyImplicitName( category, ref ) {
|
|
|
607
607
|
}
|
|
608
608
|
|
|
609
609
|
function fragileAlias( ast, safe = false ) {
|
|
610
|
+
if (this.getCurrentToken().text === '.')
|
|
611
|
+
return ast;
|
|
610
612
|
if (safe || ast.$delimited || !/^[a-zA-Z][a-zA-Z_]+$/.test( ast.id ))
|
|
611
613
|
this.warning( 'syntax-sloppy-alias', ast.location, { keyword: 'as' },
|
|
612
614
|
'Please add the keyword $(KEYWORD) in front of the alias name' );
|
|
@@ -687,8 +689,8 @@ function valuePathAst( ref ) {
|
|
|
687
689
|
const item = path.find( i => i.args && i.$syntax !== ':' );
|
|
688
690
|
if (!item)
|
|
689
691
|
return ref;
|
|
690
|
-
this.error( 'syntax-not-supported', item.location,
|
|
691
|
-
|
|
692
|
+
this.error( 'syntax-not-supported', item.location, {},
|
|
693
|
+
'Methods in expressions are not supported yet' );
|
|
692
694
|
path.broken = true;
|
|
693
695
|
path.length = 1;
|
|
694
696
|
}
|
|
@@ -1063,15 +1065,29 @@ function associationInSelectItem( art ) {
|
|
|
1063
1065
|
}
|
|
1064
1066
|
}
|
|
1065
1067
|
|
|
1066
|
-
function reportExpandInline(
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
token
|
|
1073
|
-
|
|
1074
|
-
|
|
1068
|
+
function reportExpandInline( column, isInline ) {
|
|
1069
|
+
const { name } = column;
|
|
1070
|
+
if (column.value && !column.value.path) {
|
|
1071
|
+
let token = this.getCurrentToken();
|
|
1072
|
+
// improve error location when using "inline" `.{…}` after ref (arguments and
|
|
1073
|
+
// filters not covered, not worth the effort); after an expression where
|
|
1074
|
+
// the last token is an identifier, not the `.` is wrong, but the `{`:
|
|
1075
|
+
if (isInline && !name && this._input.LT(-1).type >= this.constructor.Identifier)
|
|
1076
|
+
token = this._input.LT(2);
|
|
1077
|
+
this.error( 'syntax-unexpected-nested-proj', token,
|
|
1078
|
+
{ prop: isInline ? 'inline' : 'expand' },
|
|
1079
|
+
{ std: 'Unexpected nested $(PROP), can only be used after a reference' } );
|
|
1080
|
+
// continuation semantics:
|
|
1081
|
+
// - add elements anyway (could lead to duplicate errors as usual)
|
|
1082
|
+
// - no errors for refs inside expand/inline, but for refs in sibling expr
|
|
1083
|
+
// - think about: reference to these (sub) elements from other view
|
|
1084
|
+
}
|
|
1085
|
+
if (isInline && name) {
|
|
1086
|
+
const location = this.tokenLocation( isInline, this._input.LT(-1) );
|
|
1087
|
+
this.error( 'syntax-unexpected-alias', location, { prop: 'inline' },
|
|
1088
|
+
'Unexpected alias name before nested $(PROP)' );
|
|
1089
|
+
// continuation semantics: ignore AS
|
|
1090
|
+
}
|
|
1075
1091
|
}
|
|
1076
1092
|
|
|
1077
1093
|
function checkTypeFacet( art, argIdent ) {
|
package/lib/language/language.g4
CHANGED
|
@@ -751,7 +751,7 @@ extendType[ art, outer ] locals[ name = {} ]
|
|
|
751
751
|
{ $art.expectedKind = 'type'; $art.name = $name;
|
|
752
752
|
this.addItem( $art, $outer, 'extensions', 'extend' );
|
|
753
753
|
}
|
|
754
|
-
|
|
754
|
+
extendWithOptElementsOrType[ $art, $art ]
|
|
755
755
|
;
|
|
756
756
|
|
|
757
757
|
annotationDef[ art, outer ] locals[ name = {} ]
|
|
@@ -840,11 +840,16 @@ extendArtifact[ art, outer ] locals[ name = {}, elemName = {} ]
|
|
|
840
840
|
enumSymbolDef[ $art ]* // TODO: no EXTEND in enum? (ok, would just allow annos)
|
|
841
841
|
'}' { this.finalizeDictOrArray( $art.enum ); }
|
|
842
842
|
optionalSemi
|
|
843
|
+
|
|
|
844
|
+
// extend Art with (length: 10);
|
|
845
|
+
// `with` is required, or we could have `extend String(length:10);`.
|
|
846
|
+
typeNamedArgList[ $art ]
|
|
847
|
+
requiredSemi
|
|
843
848
|
)
|
|
844
849
|
)
|
|
845
850
|
;
|
|
846
851
|
|
|
847
|
-
|
|
852
|
+
extendWithOptElementsOrType[ art ]
|
|
848
853
|
:
|
|
849
854
|
WITH { this.noSemicolonHere(); this.docComment( $art ); }
|
|
850
855
|
annotationAssignment_ll1[ $art ]*
|
|
@@ -857,6 +862,10 @@ extendWithOptElements[ art ]
|
|
|
857
862
|
'}' { this.finalizeDictOrArray( $art.elements ); }
|
|
858
863
|
{ this.checkExtensionDict( $art.elements ); }
|
|
859
864
|
optionalSemi
|
|
865
|
+
|
|
|
866
|
+
// extend type|element Art with (length: 10);
|
|
867
|
+
typeNamedArgList[ $art ]
|
|
868
|
+
requiredSemi
|
|
860
869
|
|
|
|
861
870
|
requiredSemi
|
|
862
871
|
)
|
|
@@ -1220,7 +1229,7 @@ extendElement[ art, outer ]
|
|
|
1220
1229
|
( expected=ELEMENT { $art.expectedKind = 'element'; } )?
|
|
1221
1230
|
name=ident['Element']
|
|
1222
1231
|
{ this.addDef( $art, $outer, 'elements', 'extend', $name.id ); }
|
|
1223
|
-
|
|
1232
|
+
extendWithOptElementsOrType[ $art, $art ]
|
|
1224
1233
|
;
|
|
1225
1234
|
|
|
1226
1235
|
selectItemDef[ outer ] locals[ art ]
|
|
@@ -1246,19 +1255,20 @@ selectItemDefBody[ art, outer ]
|
|
|
1246
1255
|
e=expression { $art.value = $e.expr; }
|
|
1247
1256
|
// we cannot use 'condition' instead, as long as we allow aliases without
|
|
1248
1257
|
// AS (using rule 'ident' instead of 'identNoKeyword') -> ambiguities
|
|
1249
|
-
( AS n1=ident['Item'] { $art.name = $n1.id }
|
|
1258
|
+
( as=AS n1=ident['Item'] { $art.name = $n1.id }
|
|
1250
1259
|
| n2=ident['Item'] { $art.name = this.fragileAlias( $n2.id, true ); }
|
|
1251
1260
|
| { if (this.getCurrentToken().text !== '.') this.classifyImplicitName( 'Item', $e.expr ); }
|
|
1252
1261
|
)
|
|
1253
|
-
{ if ($art.value && !$art.value.path) this.excludeExpected( ["'.'", "'{'"] );
|
|
1262
|
+
{ if ($art.value && !$art.value.path) this.excludeExpected( ["'.'", "'{'"] );
|
|
1263
|
+
else if ($art.name) this.excludeExpected( ["'.'"] );
|
|
1264
|
+
}
|
|
1254
1265
|
(
|
|
1255
|
-
{
|
|
1266
|
+
{ this.reportExpandInline( $art, false ); }
|
|
1256
1267
|
selectItemInlineList[ $art, 'expand' ]
|
|
1257
1268
|
excludingClause[ $art ]?
|
|
1258
1269
|
// TODO: we might alternatively allow AS here
|
|
1259
1270
|
|
|
|
1260
|
-
|
|
1261
|
-
{ if ($art.value && !$art.value.path) this.reportExpandInline( 'inline' ); }
|
|
1271
|
+
{ this.reportExpandInline( $art, $as || this._input.LT(-1) ); }
|
|
1262
1272
|
DOTbeforeBRACE // ...orASTERISK
|
|
1263
1273
|
(
|
|
1264
1274
|
selectItemInlineList[ $art, 'inline' ]
|
|
@@ -1799,6 +1809,16 @@ typeRefArgs[ art ]
|
|
|
1799
1809
|
')'{ this.finalizeDictOrArray( $art['$'+'typeArgs']); }
|
|
1800
1810
|
;
|
|
1801
1811
|
|
|
1812
|
+
typeNamedArgList[ art ]
|
|
1813
|
+
:
|
|
1814
|
+
paren='('
|
|
1815
|
+
typeNamedArg[ $art ]
|
|
1816
|
+
( ',' { if (this.isStraightBefore(')')) break; } // allow ',' before ')'
|
|
1817
|
+
typeNamedArg[ $art ]
|
|
1818
|
+
)*
|
|
1819
|
+
')'
|
|
1820
|
+
;
|
|
1821
|
+
|
|
1802
1822
|
typeNamedArg[ art ] locals[ arg = '' ]
|
|
1803
1823
|
:
|
|
1804
1824
|
name=ident['paramname']
|
package/lib/main.d.ts
CHANGED
|
@@ -786,15 +786,12 @@ declare namespace compiler {
|
|
|
786
786
|
*/
|
|
787
787
|
export type CdlResult = {
|
|
788
788
|
/**
|
|
789
|
-
* Rendered model,
|
|
789
|
+
* Rendered model, including extensions.
|
|
790
790
|
*/
|
|
791
791
|
model?: string
|
|
792
792
|
/**
|
|
793
|
-
* Rendered
|
|
794
|
-
|
|
795
|
-
unappliedExtensions?: string
|
|
796
|
-
/**
|
|
797
|
-
* Rendered csn.namespace property + using directives.
|
|
793
|
+
* Rendered `csn.namespace` property + using directives.
|
|
794
|
+
* Useful to keep the `csn.namespace` property when re-compiling the to.cdl() result.
|
|
798
795
|
*/
|
|
799
796
|
namespace?: string
|
|
800
797
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"root": true,
|
|
3
|
+
"extends": "../../.eslintrc-ydkjsi.json",
|
|
4
|
+
"rules": {
|
|
5
|
+
"max-len": [ "error", {
|
|
6
|
+
"code": 180, // TODO: Remove
|
|
7
|
+
"tabWidth": 2,
|
|
8
|
+
"ignoreRegExpLiterals": false,
|
|
9
|
+
"ignoreStrings": false,
|
|
10
|
+
"ignoreTemplateLiterals": true
|
|
11
|
+
}]
|
|
12
|
+
}
|
|
13
|
+
}
|
package/lib/model/api.js
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
// Do not change at will - they are in the compiler API!
|
|
4
4
|
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
5
7
|
/**
|
|
6
8
|
* Dictionary of default traversal functions for function `traverseCsn`.
|
|
7
9
|
* It maps CSN property names to functions which are used by default
|
|
@@ -23,8 +25,8 @@ const defaultFunctions = {
|
|
|
23
25
|
actions: dictionary,
|
|
24
26
|
mixin: dictionary,
|
|
25
27
|
definitions: dictionary,
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
+
$: () => { /* do not traverse properties starting with '$' */ },
|
|
29
|
+
};
|
|
28
30
|
|
|
29
31
|
/**
|
|
30
32
|
* Traverse the CSN node `csn`.
|