@sap/cds-compiler 2.12.0 → 2.15.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 +221 -15
- package/bin/cdsc.js +125 -50
- package/bin/cdsse.js +2 -2
- package/doc/CHANGELOG_BETA.md +13 -6
- package/doc/CHANGELOG_DEPRECATED.md +22 -6
- package/doc/NameResolution.md +21 -16
- package/lib/api/main.js +47 -84
- package/lib/api/options.js +5 -6
- package/lib/api/validate.js +6 -11
- package/lib/backends.js +15 -23
- package/lib/base/dictionaries.js +0 -8
- package/lib/base/error.js +26 -0
- package/lib/base/keywords.js +7 -17
- package/lib/base/location.js +9 -4
- package/lib/base/message-registry.js +114 -18
- package/lib/base/messages.js +101 -90
- package/lib/base/model.js +2 -63
- package/lib/base/optionProcessorHelper.js +177 -123
- package/lib/checks/annotationsOData.js +12 -33
- package/lib/checks/arrayOfs.js +1 -34
- package/lib/checks/cdsPersistence.js +2 -1
- package/lib/checks/enricher.js +17 -1
- package/lib/checks/invalidTarget.js +3 -1
- package/lib/checks/managedWithoutKeys.js +3 -1
- package/lib/checks/selectItems.js +4 -4
- package/lib/checks/sql-snippets.js +27 -26
- package/lib/checks/types.js +1 -1
- package/lib/checks/validator.js +6 -11
- package/lib/compiler/assert-consistency.js +6 -3
- package/lib/compiler/base.js +1 -0
- package/lib/compiler/builtins.js +19 -6
- package/lib/compiler/checks.js +23 -60
- package/lib/compiler/cycle-detector.js +1 -1
- package/lib/compiler/define.js +1151 -0
- package/lib/compiler/extend.js +1000 -0
- package/lib/compiler/finalize-parse-cdl.js +237 -0
- package/lib/compiler/index.js +107 -39
- package/lib/compiler/kick-start.js +190 -0
- package/lib/compiler/moduleLayers.js +4 -4
- package/lib/compiler/populate.js +1227 -0
- package/lib/compiler/propagator.js +114 -46
- package/lib/compiler/resolve.js +1521 -0
- package/lib/compiler/shared.js +126 -65
- package/lib/compiler/tweak-assocs.js +535 -0
- package/lib/compiler/utils.js +197 -33
- package/lib/edm/.eslintrc.json +5 -0
- package/lib/edm/annotations/genericTranslation.js +38 -24
- package/lib/edm/annotations/preprocessAnnotations.js +2 -2
- package/lib/edm/csn2edm.js +219 -100
- package/lib/edm/edm.js +302 -230
- package/lib/edm/edmPreprocessor.js +554 -419
- package/lib/edm/edmUtils.js +138 -44
- package/lib/gen/Dictionary.json +100 -19
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +11 -1
- package/lib/gen/language.tokens +86 -83
- package/lib/gen/languageLexer.interp +10 -1
- package/lib/gen/languageLexer.js +860 -833
- package/lib/gen/languageLexer.tokens +78 -75
- package/lib/gen/languageParser.js +5765 -4480
- package/lib/json/csnVersion.js +10 -11
- package/lib/json/from-csn.js +15 -3
- package/lib/json/to-csn.js +126 -68
- package/lib/language/docCommentParser.js +4 -4
- package/lib/language/genericAntlrParser.js +123 -5
- package/lib/language/language.g4 +355 -156
- package/lib/language/multiLineStringParser.js +5 -5
- package/lib/main.d.ts +486 -59
- package/lib/main.js +41 -9
- package/lib/model/api.js +3 -1
- package/lib/model/csnRefs.js +252 -156
- package/lib/model/csnUtils.js +384 -297
- package/lib/model/enrichCsn.js +71 -29
- package/lib/model/revealInternalProperties.js +29 -8
- package/lib/model/sortViews.js +2 -1
- package/lib/modelCompare/compare.js +23 -18
- package/lib/optionProcessor.js +63 -26
- package/lib/render/manageConstraints.js +35 -32
- package/lib/render/toCdl.js +897 -947
- package/lib/render/toHdbcds.js +205 -257
- package/lib/render/toSql.js +264 -225
- package/lib/render/utils/common.js +136 -25
- package/lib/render/utils/sql.js +4 -3
- package/lib/render/utils/stringEscapes.js +111 -0
- package/lib/sql-identifier.js +1 -1
- package/lib/transform/.eslintrc.json +5 -0
- package/lib/transform/db/.eslintrc.json +3 -1
- package/lib/transform/db/applyTransformations.js +35 -12
- package/lib/transform/db/assertUnique.js +1 -1
- package/lib/transform/db/associations.js +104 -306
- package/lib/transform/db/cdsPersistence.js +2 -2
- package/lib/transform/db/constraints.js +58 -53
- package/lib/transform/db/expansion.js +60 -33
- package/lib/transform/db/flattening.js +582 -104
- package/lib/transform/db/groupByOrderBy.js +3 -1
- package/lib/transform/db/transformExists.js +66 -13
- package/lib/transform/db/views.js +11 -7
- package/lib/transform/draft/.eslintrc.json +38 -0
- package/lib/transform/{db/draft.js → draft/db.js} +6 -5
- package/lib/transform/draft/odata.js +227 -0
- package/lib/transform/forHanaNew.js +109 -208
- package/lib/transform/forOdataNew.js +59 -212
- package/lib/transform/localized.js +46 -26
- package/lib/transform/odata/toFinalBaseType.js +85 -11
- package/lib/transform/odata/typesExposure.js +147 -199
- package/lib/transform/odata/utils.js +2 -2
- package/lib/transform/transformUtilsNew.js +44 -33
- package/lib/transform/translateAssocsToJoins.js +3 -20
- package/lib/transform/universalCsn/.eslintrc.json +36 -0
- package/lib/transform/universalCsn/coreComputed.js +172 -0
- package/lib/transform/universalCsn/universalCsnEnricher.js +737 -0
- package/lib/transform/universalCsn/utils.js +63 -0
- package/lib/utils/moduleResolve.js +13 -6
- package/lib/utils/objectUtils.js +30 -0
- package/package.json +1 -1
- package/share/messages/README.md +26 -0
- package/share/messages/message-explanations.json +2 -1
- package/share/messages/syntax-expected-integer.md +37 -0
- package/lib/compiler/definer.js +0 -2361
- package/lib/compiler/resolver.js +0 -3079
- package/lib/transform/odata/attachPath.js +0 -96
- package/lib/transform/odata/expandStructKeysInAssociations.js +0 -59
- package/lib/transform/odata/generateForeignKeyElements.js +0 -261
- package/lib/transform/odata/referenceFlattener.js +0 -290
- package/lib/transform/odata/sortByAssociationDependency.js +0 -105
- package/lib/transform/odata/structuralPath.js +0 -72
- package/lib/transform/odata/structureFlattener.js +0 -171
- package/lib/transform/universalCsnEnricher.js +0 -237
package/lib/json/csnVersion.js
CHANGED
|
@@ -15,18 +15,17 @@
|
|
|
15
15
|
// 0.1.99 : Like 0.1.0, but with new-style CSN
|
|
16
16
|
// 0.2 : same as 0.1.99, but with new top-level properties: $version, meta
|
|
17
17
|
|
|
18
|
-
// Use literal version constants intentionally and not number intervals to
|
|
18
|
+
// Use literal version constants intentionally and not number intervals to
|
|
19
19
|
// record all published version strings of the core compiler.
|
|
20
|
-
const newCSNVersions = [
|
|
20
|
+
const newCSNVersions = [ '0.1.99', '0.2', '0.2.0', '1.0', '2.0' ];
|
|
21
21
|
// checks if new-csn is requested via the options of already specified in the CSN
|
|
22
22
|
// default: old-style
|
|
23
23
|
function isNewCSN(csn, options) {
|
|
24
|
-
if( (options && options.newCsn ===
|
|
24
|
+
if ( (options && options.newCsn === false) ||
|
|
25
25
|
(csn.version && !newCSNVersions.includes(csn.version.csn)) ||
|
|
26
26
|
(csn.$version && !newCSNVersions.includes(csn.$version)))
|
|
27
|
-
{
|
|
28
27
|
return false;
|
|
29
|
-
|
|
28
|
+
|
|
30
29
|
return true;
|
|
31
30
|
}
|
|
32
31
|
|
|
@@ -34,18 +33,18 @@ function checkCSNVersion(csn, options) {
|
|
|
34
33
|
if (!isNewCSN(csn, options)) {
|
|
35
34
|
// the new transformer works only with new CSN
|
|
36
35
|
const { makeMessageFunction } = require('../base/messages');
|
|
37
|
-
const { error,
|
|
36
|
+
const { error, throwWithAnyError } = makeMessageFunction(csn, options);
|
|
38
37
|
|
|
39
38
|
let errStr = 'CSN Version not supported, version tag: "';
|
|
40
|
-
errStr +=
|
|
41
|
-
errStr += (options.newCsn !== undefined) ?
|
|
39
|
+
errStr += `${ csn.version && csn.version.csn ? csn.version.csn : (csn.$version ? csn.$version : 'not available') }"`;
|
|
40
|
+
errStr += (options.newCsn !== undefined) ? `, options.newCsn: ${ options.newCsn }` : '';
|
|
42
41
|
|
|
43
42
|
error(null, null, errStr);
|
|
44
|
-
|
|
43
|
+
throwWithAnyError();
|
|
45
44
|
}
|
|
46
45
|
}
|
|
47
46
|
|
|
48
47
|
module.exports = {
|
|
49
48
|
isNewCSN,
|
|
50
|
-
checkCSNVersion
|
|
51
|
-
}
|
|
49
|
+
checkCSNVersion,
|
|
50
|
+
};
|
package/lib/json/from-csn.js
CHANGED
|
@@ -89,6 +89,8 @@
|
|
|
89
89
|
|
|
90
90
|
const { dictAdd } = require('../base/dictionaries');
|
|
91
91
|
|
|
92
|
+
const $location = Symbol.for('cds.$location');
|
|
93
|
+
|
|
92
94
|
let inExtensions = null;
|
|
93
95
|
|
|
94
96
|
let vocabInDefinitions = null; // must be reset!
|
|
@@ -150,7 +152,8 @@ const schemaClasses = {
|
|
|
150
152
|
msgId: 'syntax-csn-expected-column',
|
|
151
153
|
defaultKind: '$column',
|
|
152
154
|
validKinds: [], // pseudo kind '$column'
|
|
153
|
-
|
|
155
|
+
// A column with only as+cast.type is a new association
|
|
156
|
+
requires: [ 'ref', 'as', 'xpr', 'val', '#', 'func', 'list', 'SELECT', 'SET', 'expand' ],
|
|
154
157
|
schema: {
|
|
155
158
|
xpr: {
|
|
156
159
|
class: 'condition',
|
|
@@ -195,7 +198,7 @@ const schema = compileSchema( {
|
|
|
195
198
|
dictionaryOf: definition,
|
|
196
199
|
defaultKind: 'enum',
|
|
197
200
|
validKinds: [ 'enum' ],
|
|
198
|
-
inKind: [ 'element', 'type', 'param', 'annotation', 'annotate' ],
|
|
201
|
+
inKind: [ 'element', 'type', 'param', 'annotation', 'annotate', 'extend' ],
|
|
199
202
|
},
|
|
200
203
|
elements: {
|
|
201
204
|
dictionaryOf: definition,
|
|
@@ -661,6 +664,9 @@ const schema = compileSchema( {
|
|
|
661
664
|
ignore: true, type: ignore,
|
|
662
665
|
},
|
|
663
666
|
// TODO: should we keep $parens ?
|
|
667
|
+
$generated: {
|
|
668
|
+
type: string,
|
|
669
|
+
},
|
|
664
670
|
$: { type: ignore, ignore: true }, // including $origin
|
|
665
671
|
_: { type: ignore, ignore: true },
|
|
666
672
|
} );
|
|
@@ -931,8 +937,10 @@ function definition( def, spec, xsn, csn, name ) {
|
|
|
931
937
|
popLocation( def );
|
|
932
938
|
if (kind !== 'annotation' || prop === 'vocabularies')
|
|
933
939
|
return r;
|
|
934
|
-
if (!vocabInDefinitions)
|
|
940
|
+
if (!vocabInDefinitions) {
|
|
935
941
|
vocabInDefinitions = Object.create(null);
|
|
942
|
+
vocabInDefinitions[$location] = location();
|
|
943
|
+
}
|
|
936
944
|
vocabInDefinitions[name] = r; // deprecated: anno def in 'definitions'
|
|
937
945
|
return undefined;
|
|
938
946
|
|
|
@@ -957,6 +965,7 @@ function dictionaryOf( elementFct ) {
|
|
|
957
965
|
return ignore( dict );
|
|
958
966
|
}
|
|
959
967
|
const r = Object.create(null);
|
|
968
|
+
r[$location] = location();
|
|
960
969
|
const allNames = Object.keys( dict );
|
|
961
970
|
if (!allNames.length)
|
|
962
971
|
return r; // {} in one JSON line
|
|
@@ -980,6 +989,7 @@ function keys( array, spec, xsn ) {
|
|
|
980
989
|
if (!isArray( array, spec ))
|
|
981
990
|
return;
|
|
982
991
|
const r = Object.create(null);
|
|
992
|
+
r[$location] = location();
|
|
983
993
|
++virtualLine;
|
|
984
994
|
for (const def of array) {
|
|
985
995
|
const id = def.as || implicitName( def.ref );
|
|
@@ -1177,6 +1187,7 @@ function annoValue( val, spec ) {
|
|
|
1177
1187
|
if (lit !== 'object')
|
|
1178
1188
|
return { val, literal: lit, location: location() };
|
|
1179
1189
|
if (Array.isArray( val )) {
|
|
1190
|
+
/** @type {string|boolean} */
|
|
1180
1191
|
let seenEllipsis = false;
|
|
1181
1192
|
if (arrayLevelCount > 0) { // TODO: also inside structure (possible in CSN!)
|
|
1182
1193
|
if (val.some( isEllipsis )) {
|
|
@@ -1435,6 +1446,7 @@ function excluding( array, spec, xsn ) {
|
|
|
1435
1446
|
if (!isArray( array, spec ))
|
|
1436
1447
|
return;
|
|
1437
1448
|
const r = Object.create(null);
|
|
1449
|
+
r[$location] = location();
|
|
1438
1450
|
++virtualLine;
|
|
1439
1451
|
for (const ex of array) {
|
|
1440
1452
|
const id = string( ex, spec ) || '';
|
package/lib/json/to-csn.js
CHANGED
|
@@ -57,7 +57,7 @@ const transformers = {
|
|
|
57
57
|
key: value,
|
|
58
58
|
unique: value,
|
|
59
59
|
masked: value,
|
|
60
|
-
params
|
|
60
|
+
params,
|
|
61
61
|
// early expression / query properties -------------------------------------
|
|
62
62
|
op: o => ((o.val !== 'SELECT' && o.val !== '$query') ? o.val : undefined),
|
|
63
63
|
from, // before elements!
|
|
@@ -185,7 +185,7 @@ const propertyOrder = (function orderPositions() {
|
|
|
185
185
|
|
|
186
186
|
// sync with definition in from-csn.js:
|
|
187
187
|
const typeProperties = [
|
|
188
|
-
'target', 'elements', 'enum', 'items',
|
|
188
|
+
'target', 'elements', 'enum', 'items', // TODO: notNull?
|
|
189
189
|
'type', 'length', 'precision', 'scale', 'srid', 'localized',
|
|
190
190
|
'foreignKeys', 'on', // for explicit ON/keys with REDIRECTED
|
|
191
191
|
];
|
|
@@ -204,7 +204,10 @@ const operators = {
|
|
|
204
204
|
when: exprs => [ 'when', ...exprs[0], 'then', ...exprs[1] ],
|
|
205
205
|
case: exprs => [ 'case' ].concat( ...exprs, [ 'end' ] ),
|
|
206
206
|
over: exprs => [ 'over', { xpr: [].concat( ...exprs ) } ],
|
|
207
|
-
orderBy: exprs => [
|
|
207
|
+
orderBy: exprs => [ // ORDER BY in generic functions
|
|
208
|
+
...exprs[0], ...operators.overOrderBy(exprs.slice(1)),
|
|
209
|
+
],
|
|
210
|
+
overOrderBy: exprs => [ // ORDER BY in OVER() clause
|
|
208
211
|
'order', 'by', ...exprs[0].concat( ...exprs.slice(1).map( e => [ ',', ...e ] ) ),
|
|
209
212
|
],
|
|
210
213
|
partitionBy: exprs => [
|
|
@@ -277,7 +280,7 @@ function sortCsn( csn, cloneOptions = false ) {
|
|
|
277
280
|
}
|
|
278
281
|
|
|
279
282
|
/**
|
|
280
|
-
* Check
|
|
283
|
+
* Check whether the given object has non enumerable property.
|
|
281
284
|
* Ensure that we don't take it from the prototype, only "directly" - we accidentally
|
|
282
285
|
* cloned elements with a cds.linked input otherwise.
|
|
283
286
|
*
|
|
@@ -401,8 +404,6 @@ function usings( srcDict ) {
|
|
|
401
404
|
* @param {object} csn
|
|
402
405
|
* @param {object} model
|
|
403
406
|
*/
|
|
404
|
-
|
|
405
|
-
|
|
406
407
|
function extensions( node, csn, model ) {
|
|
407
408
|
if (model.kind && model.kind !== 'source')
|
|
408
409
|
return undefined;
|
|
@@ -621,10 +622,7 @@ function targetAspect( val, csn, node ) {
|
|
|
621
622
|
if (val.$inferred)
|
|
622
623
|
return undefined;
|
|
623
624
|
if (node.target) {
|
|
624
|
-
csn.$origin = {
|
|
625
|
-
if (node.cardinality)
|
|
626
|
-
csn.$origin.cardinality = standard( node.cardinality );
|
|
627
|
-
csn.$origin.target = (val.elements) ? standard( val ) : artifactRef( val, true );
|
|
625
|
+
csn.$origin = { target: (val.elements) ? standard( val ) : artifactRef( val, true ) };
|
|
628
626
|
return undefined;
|
|
629
627
|
}
|
|
630
628
|
}
|
|
@@ -643,7 +641,7 @@ function target( val, _csn, node ) {
|
|
|
643
641
|
val = node._origin.target;
|
|
644
642
|
if (val.elements)
|
|
645
643
|
return standard( val ); // elements in target (parse-cdl)
|
|
646
|
-
if (!universalCsn || node.on)
|
|
644
|
+
if (!universalCsn || gensrcFlavor || node.on)
|
|
647
645
|
return artifactRef( val, true );
|
|
648
646
|
const tref = artifactRef( val, true );
|
|
649
647
|
const proto = node.type && !node.type.$inferred ? node.type._artifact : node._origin;
|
|
@@ -779,7 +777,7 @@ function addLocation( loc, csn ) {
|
|
|
779
777
|
// Remove endLine/endCol:
|
|
780
778
|
// Reasoning: $location is mostly attached to definitions/members but the name
|
|
781
779
|
// is often not the reason for an error or warning. So we gain little benefit for
|
|
782
|
-
// two more properties.
|
|
780
|
+
// two more properties. It is also an indication that the location is not exact.
|
|
783
781
|
const val = { file: loc.file, line: loc.line, col: loc.col };
|
|
784
782
|
Object.defineProperty( csn, '$location', {
|
|
785
783
|
value: val, configurable: true, writable: true, enumerable: withLocations,
|
|
@@ -807,6 +805,13 @@ function actions( dict ) {
|
|
|
807
805
|
: undefined;
|
|
808
806
|
}
|
|
809
807
|
|
|
808
|
+
function params( dict ) {
|
|
809
|
+
const keys = Object.keys( dict );
|
|
810
|
+
return (keys.length)
|
|
811
|
+
? insertOrderDict( dict )
|
|
812
|
+
: undefined;
|
|
813
|
+
}
|
|
814
|
+
|
|
810
815
|
function dictionary( dict, keys, prop ) {
|
|
811
816
|
const csn = Object.create( dictionaryPrototype );
|
|
812
817
|
for (const name of keys) {
|
|
@@ -863,7 +868,7 @@ function definition( art, _csn, _node, prop ) {
|
|
|
863
868
|
c.returns = { elements: elems };
|
|
864
869
|
}
|
|
865
870
|
// precondition already fulfilled: art.kind !== 'key'
|
|
866
|
-
addOrigin( c, art, art
|
|
871
|
+
addOrigin( c, art, art );
|
|
867
872
|
return c;
|
|
868
873
|
}
|
|
869
874
|
|
|
@@ -876,7 +881,8 @@ function includesOrigin( includes, art ) {
|
|
|
876
881
|
for (const incl of includes.slice(1)) {
|
|
877
882
|
const aspect = incl._artifact;
|
|
878
883
|
for (const prop in aspect) {
|
|
879
|
-
if (prop.charAt(0) === '@'
|
|
884
|
+
if ((prop.charAt(0) === '@' || prop === 'doc') &&
|
|
885
|
+
(!art[prop] || art[prop].$inferred)) {
|
|
880
886
|
const anno = aspect[prop];
|
|
881
887
|
if (anno.val !== null)
|
|
882
888
|
// matererialize non-null annos (whether direct or inherited)
|
|
@@ -887,9 +893,23 @@ function includesOrigin( includes, art ) {
|
|
|
887
893
|
return (Object.keys( result ).length === 1) ? $origin : result;
|
|
888
894
|
}
|
|
889
895
|
|
|
890
|
-
function addOrigin( csn, xsn,
|
|
891
|
-
if (!universalCsn
|
|
896
|
+
function addOrigin( csn, xsn, node ) {
|
|
897
|
+
if (!universalCsn)
|
|
898
|
+
return;
|
|
899
|
+
if (hasExplicitProp( xsn.type, 'cast' )) {
|
|
900
|
+
const main = xsn._main || xsn;
|
|
901
|
+
let count = 0;
|
|
902
|
+
let source = xsn;
|
|
903
|
+
while (source && source._main === main) {
|
|
904
|
+
source = source.value && source.value._artifact;
|
|
905
|
+
++count;
|
|
906
|
+
}
|
|
907
|
+
if (count > 0 && source && source.kind !== 'builtin')
|
|
908
|
+
csn.$source = originRef( source, xsn );
|
|
909
|
+
else if (count > 1)
|
|
910
|
+
csn.$source = null;
|
|
892
911
|
return;
|
|
912
|
+
}
|
|
893
913
|
if (xsn._from) {
|
|
894
914
|
const source = xsn._from[0]._origin;
|
|
895
915
|
csn.$origin = originRef( source );
|
|
@@ -903,23 +923,22 @@ function addOrigin( csn, xsn, origin ) {
|
|
|
903
923
|
csn.$origin = includesOrigin( xsn.includes, xsn );
|
|
904
924
|
return;
|
|
905
925
|
}
|
|
906
|
-
|
|
926
|
+
let origin = getOrigin( node );
|
|
927
|
+
if (xsn.$inferred === 'composition-entity') {
|
|
928
|
+
csn.$origin = originRef( origin, xsn );
|
|
929
|
+
return;
|
|
930
|
+
}
|
|
931
|
+
else if (!isMember( xsn ) || xsn.kind === 'select') {
|
|
907
932
|
return;
|
|
908
933
|
}
|
|
934
|
+
// from here on: member:
|
|
909
935
|
const parent = getParent( xsn );
|
|
910
936
|
const parentOrigin = getOrigin( parent );
|
|
911
|
-
if (!
|
|
912
|
-
if (parentOrigin && (
|
|
937
|
+
if (!origin) {
|
|
938
|
+
if (parentOrigin && !(parent.enum && !parent.$origin && parent.type))
|
|
913
939
|
csn.$origin = null;
|
|
914
940
|
return;
|
|
915
941
|
}
|
|
916
|
-
// Skip all proxies which do not make it into the CSN, as there are no
|
|
917
|
-
// individual annotations or redirection targets on it:
|
|
918
|
-
while (origin._parent && origin._parent.$expand === 'origin')
|
|
919
|
-
origin = origin._origin || origin.type._artifact;
|
|
920
|
-
// The while loop is not only for the else case below: when setting implicit
|
|
921
|
-
// prototypes, it is important that we do not have to follow the prototypes of
|
|
922
|
-
// other object; we would need to ensure a right order to avoid issues otherwise.
|
|
923
942
|
if (parentOrigin === getParent( origin )) {
|
|
924
943
|
// implicit prototype or shortened reference
|
|
925
944
|
const { id } = origin.name || {};
|
|
@@ -928,16 +947,21 @@ function addOrigin( csn, xsn, origin ) {
|
|
|
928
947
|
return;
|
|
929
948
|
}
|
|
930
949
|
if (origin.kind === 'mixin') {
|
|
931
|
-
|
|
932
|
-
csn
|
|
950
|
+
set( 'type', csn, origin );
|
|
951
|
+
set( 'cardinality', csn, origin );
|
|
952
|
+
// currently, target and on are always set - nothing to do here
|
|
933
953
|
return;
|
|
934
954
|
}
|
|
955
|
+
// Skip all proxies which do not make it into the CSN, as there are no
|
|
956
|
+
// individual annotations or redirection targets on it:
|
|
957
|
+
while (origin._parent && origin._parent.$expand === 'origin')
|
|
958
|
+
origin = origin._origin || origin.type._artifact;
|
|
935
959
|
const ref = originRef( origin, xsn );
|
|
936
960
|
if (ref) {
|
|
937
961
|
csn.$origin = ref;
|
|
938
962
|
return;
|
|
939
963
|
}
|
|
940
|
-
// An element of a query with a query in FROM:
|
|
964
|
+
// An element of a query with a query in FROM: -----------------------------
|
|
941
965
|
const anon = definition( origin ); // use $origin: {...} if necessary
|
|
942
966
|
// as there are no implicit $origin prototypes on sub query elements (yet),
|
|
943
967
|
// we do not have to care about $origin not being set
|
|
@@ -945,15 +969,26 @@ function addOrigin( csn, xsn, origin ) {
|
|
|
945
969
|
if ($origin && typeof $origin === 'object' && !Array.isArray( $origin )) {
|
|
946
970
|
// repeated anon: flatten
|
|
947
971
|
csn.$origin = Object.assign( $origin, anon );
|
|
972
|
+
return;
|
|
973
|
+
}
|
|
974
|
+
// Annotations and 'doc' must keep the distinction between direct or inherited,
|
|
975
|
+
// other properties can as well be set as direct element properties
|
|
976
|
+
const annos = {};
|
|
977
|
+
for (const prop of Object.keys( anon )) {
|
|
978
|
+
if (prop.charAt(0) === '@' || prop === 'doc')
|
|
979
|
+
annos[prop] = anon[prop];
|
|
980
|
+
else if (prop === '$source')
|
|
981
|
+
csn[prop] = anon[prop]; // overwrite from inner
|
|
982
|
+
else if (prop !== '$location' && prop !== '$origin' && !(prop in csn))
|
|
983
|
+
csn[prop] = anon[prop];
|
|
948
984
|
}
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
addOrigin( csn, xsn, origin._origin );
|
|
985
|
+
if (Object.keys( annos ).length) {
|
|
986
|
+
if (!csn.type && $origin)
|
|
987
|
+
annos.$origin = $origin;
|
|
988
|
+
csn.$origin = annos;
|
|
954
989
|
}
|
|
955
|
-
else {
|
|
956
|
-
csn
|
|
990
|
+
else if (!csn.type) {
|
|
991
|
+
addOrigin( csn, xsn, origin );
|
|
957
992
|
}
|
|
958
993
|
}
|
|
959
994
|
|
|
@@ -963,10 +998,27 @@ function getParent( art ) {
|
|
|
963
998
|
return (main && parent === main._leadingQuery) ? main : parent;
|
|
964
999
|
}
|
|
965
1000
|
|
|
1001
|
+
function isMember( art ) {
|
|
1002
|
+
// TODO: introduce art.kind = '$aspect' for anonymous aspect (is a member) ?
|
|
1003
|
+
return !!(art._main || art._outer);
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
// function getDefinition( art ) {
|
|
1007
|
+
// let main = art._main || art;
|
|
1008
|
+
// while (main._outer) // anonymous aspect
|
|
1009
|
+
// main = main._outer._main;
|
|
1010
|
+
// return main;
|
|
1011
|
+
// }
|
|
1012
|
+
|
|
1013
|
+
// XSN `_origin` is (currently?) not the same as _origin in Universal CSN...
|
|
1014
|
+
// TODO: at least with expand, set it correctly (alias: keep, assoc: to entity, $builtin: no)
|
|
966
1015
|
function getOrigin( art ) {
|
|
967
|
-
if (art
|
|
968
|
-
return
|
|
969
|
-
|
|
1016
|
+
if (art.$noOrigin)
|
|
1017
|
+
return undefined;
|
|
1018
|
+
const { _origin } = art;
|
|
1019
|
+
if (_origin)
|
|
1020
|
+
return (_origin.kind === 'builtin') ? undefined : _origin; // not $dollarVariable
|
|
1021
|
+
if (hasExplicitProp( art.type, 'cast' ))
|
|
970
1022
|
return art.type._artifact;
|
|
971
1023
|
if (art.includes)
|
|
972
1024
|
return art.includes[0]._artifact;
|
|
@@ -975,31 +1027,31 @@ function getOrigin( art ) {
|
|
|
975
1027
|
return undefined;
|
|
976
1028
|
}
|
|
977
1029
|
|
|
978
|
-
function hasExplicitProp( ref ) {
|
|
979
|
-
return ref && !ref.$inferred;
|
|
1030
|
+
function hasExplicitProp( ref, alsoLikeExplicit ) {
|
|
1031
|
+
return ref && (!ref.$inferred || ref.$inferred === alsoLikeExplicit );
|
|
980
1032
|
}
|
|
981
1033
|
|
|
982
1034
|
function originRef( art, user ) {
|
|
983
1035
|
const r = [];
|
|
984
|
-
// do not use name.element, as we allow `.`s in name
|
|
1036
|
+
// do not use name.element, as we might allow `.`s in name
|
|
985
1037
|
let parent = art;
|
|
986
|
-
|
|
1038
|
+
if (parent._outer && parent.kind === 'aspect')
|
|
1039
|
+
r.push( { target: true } );
|
|
1040
|
+
while (isMember( parent ) && parent.kind !== 'select') {
|
|
987
1041
|
const nkind = normalizedKind[parent.kind];
|
|
988
|
-
|
|
1042
|
+
const name = parent.name || parent._outer.name;
|
|
1043
|
+
if (name.id || !r.length)
|
|
989
1044
|
// Return parameter is in XSN - kind: 'param', name.id: ''
|
|
990
1045
|
// eslint-disable-next-line no-nested-ternary, max-len
|
|
991
|
-
r.push( !nkind ?
|
|
1046
|
+
r.push( !nkind ? name.id : name.id ? { [nkind]: name.id } : { returns: true } );
|
|
992
1047
|
parent = parent._parent;
|
|
993
1048
|
}
|
|
994
1049
|
if (user && parent._main && parent._main === user._main && parent !== user._main._leadingQuery)
|
|
995
1050
|
// well, an element of an query in FROM (TODO: try with sub elem), but not the leading query
|
|
996
|
-
return
|
|
1051
|
+
return false; // do not write, probably use $origin: {...}
|
|
997
1052
|
// for sub query in FROM in sub query in FROM, we could condense the info
|
|
998
1053
|
|
|
999
|
-
|
|
1000
|
-
if (r.length === 1 && normalizedKind[art.kind] === 'action')
|
|
1001
|
-
return [ art.name.absolute, art.name.id ];
|
|
1002
|
-
r.push( art.name.absolute );
|
|
1054
|
+
r.push( parent.name.absolute );
|
|
1003
1055
|
r.reverse();
|
|
1004
1056
|
return r;
|
|
1005
1057
|
}
|
|
@@ -1018,6 +1070,9 @@ function kind( k, csn, node ) {
|
|
|
1018
1070
|
else if (k === 'action' && node._main && universalCsn && node.$inferred) {
|
|
1019
1071
|
// Universal CSN: do not mention kind: 'action' on expanded action
|
|
1020
1072
|
}
|
|
1073
|
+
else if (k === 'aspect' && (node._outer || node.$inferred)) {
|
|
1074
|
+
return; // do not show kind for anonymous aspect
|
|
1075
|
+
}
|
|
1021
1076
|
else if (![
|
|
1022
1077
|
'element', 'key', 'param', 'enum', 'select', '$join',
|
|
1023
1078
|
'$tableAlias', 'annotation', 'mixin',
|
|
@@ -1032,26 +1087,20 @@ function kind( k, csn, node ) {
|
|
|
1032
1087
|
function type( node, csn, xsn ) {
|
|
1033
1088
|
if (!universalCsn)
|
|
1034
1089
|
return artifactRef( node, !node.$extra );
|
|
1035
|
-
if (node.$inferred)
|
|
1090
|
+
if (node.$inferred && node.$inferred !== 'cast')
|
|
1036
1091
|
return undefined;
|
|
1037
1092
|
if (xsn._origin) {
|
|
1038
1093
|
if (xsn._origin.$inferred === 'REDIRECTED') { // auto-redirected user-provided target
|
|
1039
1094
|
csn.$origin = definition( xsn._origin );
|
|
1040
|
-
return undefined;
|
|
1041
1095
|
}
|
|
1042
1096
|
}
|
|
1043
|
-
else if ( xsn.targetAspect && xsn.target ) {
|
|
1044
|
-
// type moved to $origin: { type: … }
|
|
1045
|
-
return undefined;
|
|
1046
|
-
}
|
|
1047
1097
|
return artifactRef( node, !node.$extra );
|
|
1048
1098
|
}
|
|
1049
1099
|
|
|
1050
|
-
function cardinality( node
|
|
1100
|
+
function cardinality( node ) {
|
|
1051
1101
|
if (!universalCsn)
|
|
1052
1102
|
return standard( node );
|
|
1053
|
-
|
|
1054
|
-
if (node.$inferred || xsn.targetAspect && !xsn.targetAspect.$inferred && xsn.target)
|
|
1103
|
+
if (node.$inferred)
|
|
1055
1104
|
return undefined;
|
|
1056
1105
|
return standard( node );
|
|
1057
1106
|
}
|
|
@@ -1159,8 +1208,12 @@ function value( node ) {
|
|
|
1159
1208
|
// "Short" value form, e.g. for annotation assignments
|
|
1160
1209
|
if (!node)
|
|
1161
1210
|
return true; // `@aBool` short for `@aBool: true`
|
|
1162
|
-
if (universalCsn && node.$inferred
|
|
1163
|
-
|
|
1211
|
+
if (universalCsn && node.$inferred) {
|
|
1212
|
+
if (node.$inferred === 'prop' || node.$inferred === '$generated') // via propagator.js
|
|
1213
|
+
return undefined;
|
|
1214
|
+
else if (node.$inferred === 'NULL')
|
|
1215
|
+
return null;
|
|
1216
|
+
}
|
|
1164
1217
|
if (node.$inferred && gensrcFlavor)
|
|
1165
1218
|
return undefined;
|
|
1166
1219
|
if (node.path) {
|
|
@@ -1329,7 +1382,7 @@ function query( node, csn, xsn, _prop, expectedParens = 0 ) {
|
|
|
1329
1382
|
if (node.op.val === 'SELECT') {
|
|
1330
1383
|
if (xsn && xsn.query === node && xsn.$syntax === 'projection' &&
|
|
1331
1384
|
node.from && node.from.path && !projectionAsQuery) {
|
|
1332
|
-
csn.projection = standard( node );
|
|
1385
|
+
csn.projection = addLocation( node.location, standard( node ) );
|
|
1333
1386
|
return undefined;
|
|
1334
1387
|
}
|
|
1335
1388
|
const select = { SELECT: extra( standard( node ), node, expectedParens ) };
|
|
@@ -1351,6 +1404,9 @@ function query( node, csn, xsn, _prop, expectedParens = 0 ) {
|
|
|
1351
1404
|
gensrcFlavor = gensrcSaved;
|
|
1352
1405
|
}
|
|
1353
1406
|
}
|
|
1407
|
+
// the $location is better put inside the SELECT value, not as sibling (but
|
|
1408
|
+
// we keep it as sibling also for compatibility):
|
|
1409
|
+
addLocation( node.location, select.SELECT );
|
|
1354
1410
|
return addLocation( node.location, select );
|
|
1355
1411
|
}
|
|
1356
1412
|
const union = {};
|
|
@@ -1399,11 +1455,13 @@ function from( node ) {
|
|
|
1399
1455
|
else if (node.query) {
|
|
1400
1456
|
return addExplicitAs( query( node.query, null, null, null, 1 ), node.name );
|
|
1401
1457
|
}
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1458
|
+
|
|
1459
|
+
const ref = artifactRef( node, false );
|
|
1460
|
+
return extra( addExplicitAs( ref, node.name, (id) => {
|
|
1461
|
+
let name = ref.ref ? ref.ref[ref.ref.length - 1] : ref;
|
|
1462
|
+
name = name && name.id || name;
|
|
1463
|
+
if (!name)
|
|
1464
|
+
return false;
|
|
1407
1465
|
const dot = name.lastIndexOf('.');
|
|
1408
1466
|
return name.substring( dot + 1 ) !== id;
|
|
1409
1467
|
}), node );
|
|
@@ -1452,7 +1510,7 @@ function addElementAsColumn( elem, cols ) {
|
|
|
1452
1510
|
}
|
|
1453
1511
|
|
|
1454
1512
|
function orderBy( node ) {
|
|
1455
|
-
const expr = expression( node
|
|
1513
|
+
const expr = expression( node );
|
|
1456
1514
|
if (node.sort)
|
|
1457
1515
|
expr.sort = node.sort.val;
|
|
1458
1516
|
if (node.nulls)
|
|
@@ -36,14 +36,14 @@ function parseDocComment(comment) {
|
|
|
36
36
|
else if (lines.length === 2) {
|
|
37
37
|
// Comment that is essentially just a header + footer.
|
|
38
38
|
// First line, i.e. header, is always trimmed from left.
|
|
39
|
-
lines[0] = lines[0].
|
|
39
|
+
lines[0] = lines[0].trimStart();
|
|
40
40
|
|
|
41
41
|
// If the second line starts with an asterisk then remove it.
|
|
42
42
|
// Otherwise trim all whitespace.
|
|
43
43
|
if ((/^\s*[*]/.test(lines[1])))
|
|
44
44
|
lines[1] = removeFence(lines[1]);
|
|
45
45
|
else
|
|
46
|
-
lines[1] = lines[1].
|
|
46
|
+
lines[1] = lines[1].trimStart();
|
|
47
47
|
}
|
|
48
48
|
else {
|
|
49
49
|
const firstNonEmptyLine = lines.find((line, index) => index !== 0 && /[^\s]/.test(line)) || '';
|
|
@@ -127,8 +127,8 @@ function removeFooterFence(line) {
|
|
|
127
127
|
* @param {string[]} lines
|
|
128
128
|
*/
|
|
129
129
|
function isFencedComment(lines) {
|
|
130
|
-
const index = lines.findIndex((line,
|
|
131
|
-
const exclude = (
|
|
130
|
+
const index = lines.findIndex((line, i) => {
|
|
131
|
+
const exclude = (i === 0 || i === lines.length - 1);
|
|
132
132
|
return !exclude && !(/^\s*[*]/.test(line));
|
|
133
133
|
});
|
|
134
134
|
return index === -1 && lines.length > 2;
|