@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
package/lib/base/keywords.js
CHANGED
|
@@ -190,7 +190,7 @@ module.exports = {
|
|
|
190
190
|
// SAP HANA keywords, used for smart quoting in to-hdi.plain
|
|
191
191
|
// Taken from https://help.sap.com/viewer/7c78579ce9b14a669c1f3295b0d8ca16/Cloud/en-US/28bcd6af3eb6437892719f7c27a8a285.html
|
|
192
192
|
// Better use keywords in ptime/query/parser/syntax/qp_keyword.cc minus those
|
|
193
|
-
// in rule unreserved_keyword_column (=…_common -
|
|
193
|
+
// in rule unreserved_keyword_column (=…_common - 'CONSTRAINT') in
|
|
194
194
|
// ptime/query/parser/syntax/qp_gram.y of the HANA sources.
|
|
195
195
|
hana: [
|
|
196
196
|
'ABAPITAB',
|
|
@@ -209,12 +209,16 @@ module.exports = {
|
|
|
209
209
|
'ABAP_STRING',
|
|
210
210
|
'ABAP_TIME',
|
|
211
211
|
'ABAP_XSTRING',
|
|
212
|
+
'ABS',
|
|
213
|
+
'ACOS',
|
|
212
214
|
'ADD_DAYS',
|
|
213
215
|
'ADD_MONTHS',
|
|
214
216
|
'ADD_SECONDS',
|
|
215
217
|
'ADD_YEARS',
|
|
218
|
+
'ADJACENCY',
|
|
216
219
|
'ADOPT',
|
|
217
220
|
'ALL',
|
|
221
|
+
'ALPHANUM',
|
|
218
222
|
'ALTER',
|
|
219
223
|
'ANALYTIC',
|
|
220
224
|
'ANY',
|
|
@@ -222,7 +226,11 @@ module.exports = {
|
|
|
222
226
|
'ARRAY',
|
|
223
227
|
'ARRAY_AGG',
|
|
224
228
|
'AS',
|
|
229
|
+
'ASCII',
|
|
230
|
+
'ASIN',
|
|
225
231
|
'AT',
|
|
232
|
+
'ATAN',
|
|
233
|
+
'ATAN2',
|
|
226
234
|
'AUTHORIZATION',
|
|
227
235
|
'AUTO',
|
|
228
236
|
'AVG',
|
|
@@ -240,6 +248,9 @@ module.exports = {
|
|
|
240
248
|
'BIND_DOUBLE',
|
|
241
249
|
'BIND_NCHAR',
|
|
242
250
|
'BIND_REAL',
|
|
251
|
+
'BINTEXT',
|
|
252
|
+
'BINTOHEX',
|
|
253
|
+
'BITAND',
|
|
243
254
|
'BLOB',
|
|
244
255
|
'BOOLEAN',
|
|
245
256
|
'BOTH',
|
|
@@ -249,9 +260,25 @@ module.exports = {
|
|
|
249
260
|
'BY',
|
|
250
261
|
'CASE',
|
|
251
262
|
'CAST',
|
|
263
|
+
'CEIL',
|
|
264
|
+
'CEILING',
|
|
265
|
+
'CE_AGGREGATION',
|
|
252
266
|
'CE_CALC',
|
|
267
|
+
'CE_CALC_VIEW',
|
|
268
|
+
'CE_COLUMN_TABLE',
|
|
269
|
+
'CE_COMM2R',
|
|
270
|
+
'CE_CONVERSION',
|
|
271
|
+
'CE_FULL_OUTER_JOIN',
|
|
253
272
|
'CE_JOIN',
|
|
273
|
+
'CE_JOIN_VIEW',
|
|
274
|
+
'CE_LEFT_OUTER_JOIN',
|
|
275
|
+
'CE_MERGE',
|
|
276
|
+
'CE_OLAP_VIEW',
|
|
277
|
+
'CE_PARTITION',
|
|
254
278
|
'CE_PROJECTION',
|
|
279
|
+
'CE_RIGHT_OUTER_JOIN',
|
|
280
|
+
'CE_UNION_ALL',
|
|
281
|
+
'CE_VERTICAL_UNION',
|
|
255
282
|
'CHAR',
|
|
256
283
|
'CHARACTER',
|
|
257
284
|
'CLOB',
|
|
@@ -262,8 +289,12 @@ module.exports = {
|
|
|
262
289
|
'CONNECT',
|
|
263
290
|
'CONSTANT',
|
|
264
291
|
'CONSTRAINT',
|
|
292
|
+
'COS',
|
|
293
|
+
'COSH',
|
|
294
|
+
'COT',
|
|
265
295
|
'COUNT',
|
|
266
296
|
'CROSS',
|
|
297
|
+
'CS_ALPHANUM',
|
|
267
298
|
'CS_DATE',
|
|
268
299
|
'CS_DAYDATE',
|
|
269
300
|
'CS_DECIMAL_FLOAT',
|
|
@@ -285,6 +316,7 @@ module.exports = {
|
|
|
285
316
|
'CS_TEXT',
|
|
286
317
|
'CS_TEXT_AE',
|
|
287
318
|
'CS_TIME',
|
|
319
|
+
'CS_ZONE',
|
|
288
320
|
'CUBE',
|
|
289
321
|
'CUME_DIST',
|
|
290
322
|
'CURDATE',
|
|
@@ -313,6 +345,7 @@ module.exports = {
|
|
|
313
345
|
'DAYOFWEEK',
|
|
314
346
|
'DAYS_BETWEEN',
|
|
315
347
|
'DDIC_ACCP',
|
|
348
|
+
'DDIC_ALNM',
|
|
316
349
|
'DDIC_CDAY',
|
|
317
350
|
'DDIC_CHAR',
|
|
318
351
|
'DDIC_CLNT',
|
|
@@ -373,12 +406,14 @@ module.exports = {
|
|
|
373
406
|
'EXCEPTION',
|
|
374
407
|
'EXEC',
|
|
375
408
|
'EXISTS',
|
|
409
|
+
'EXP',
|
|
376
410
|
'EXTRACT',
|
|
377
411
|
'FALSE',
|
|
378
412
|
'FILTER',
|
|
379
413
|
'FIRST_VALUE',
|
|
380
414
|
'FLATTEN',
|
|
381
415
|
'FLOAT',
|
|
416
|
+
'FLOOR',
|
|
382
417
|
'FOR',
|
|
383
418
|
'FORCE_FIRST_PASSWORD_CHANGE',
|
|
384
419
|
'FREESTYLESEARCHATTRIBUTE',
|
|
@@ -390,6 +425,7 @@ module.exports = {
|
|
|
390
425
|
'GROUPING',
|
|
391
426
|
'GROUPING_FILTER',
|
|
392
427
|
'GROUPING_ID',
|
|
428
|
+
'GROUP_SCORE',
|
|
393
429
|
'HASANYPRIVILEGES',
|
|
394
430
|
'HASSYSTEMPRIVILEGE',
|
|
395
431
|
'HAVING',
|
|
@@ -403,6 +439,7 @@ module.exports = {
|
|
|
403
439
|
'HIERARCHY_SIBLINGS',
|
|
404
440
|
'HIERARCHY_SPANTREE',
|
|
405
441
|
'HIERARCHY_TEMPORAL',
|
|
442
|
+
'HIGHLIGHTED',
|
|
406
443
|
'HILBERT',
|
|
407
444
|
'HOST',
|
|
408
445
|
'HOUR',
|
|
@@ -426,10 +463,12 @@ module.exports = {
|
|
|
426
463
|
'JSON_TABLE',
|
|
427
464
|
'JSON_VALUE',
|
|
428
465
|
'LAG',
|
|
466
|
+
'LANGUAGE',
|
|
429
467
|
'LAST_DAY',
|
|
430
468
|
'LAST_VALUE',
|
|
431
469
|
'LATERAL',
|
|
432
470
|
'LAYOUT',
|
|
471
|
+
'LCASE',
|
|
433
472
|
'LEAD',
|
|
434
473
|
'LEADING',
|
|
435
474
|
'LEAST',
|
|
@@ -439,10 +478,13 @@ module.exports = {
|
|
|
439
478
|
'LENGTHB',
|
|
440
479
|
'LEVELS',
|
|
441
480
|
'LIMIT',
|
|
481
|
+
'LN',
|
|
442
482
|
'LOCATE',
|
|
443
483
|
'LOCATE_REGEXPR',
|
|
484
|
+
'LOG',
|
|
444
485
|
'LONGDATE',
|
|
445
486
|
'LOOP',
|
|
487
|
+
'LOWER',
|
|
446
488
|
'LPAD',
|
|
447
489
|
'LTRIM',
|
|
448
490
|
'MAP',
|
|
@@ -450,9 +492,11 @@ module.exports = {
|
|
|
450
492
|
'MAP_REDUCE',
|
|
451
493
|
'MAX',
|
|
452
494
|
'MEASURES',
|
|
495
|
+
'MIMETYPE',
|
|
453
496
|
'MIN',
|
|
454
497
|
'MINUS',
|
|
455
498
|
'MINUTE',
|
|
499
|
+
'MOD',
|
|
456
500
|
'MONTH',
|
|
457
501
|
'MULTIPARENT',
|
|
458
502
|
'NATURAL',
|
|
@@ -486,9 +530,11 @@ module.exports = {
|
|
|
486
530
|
'PERCENTILE_DISC',
|
|
487
531
|
'PERCENT_RANK',
|
|
488
532
|
'PLAIN',
|
|
533
|
+
'POWER',
|
|
489
534
|
'PRIOR',
|
|
490
535
|
'PRODUCT',
|
|
491
536
|
'RANGE',
|
|
537
|
+
'RANGE_RESTRICTION',
|
|
492
538
|
'RANK',
|
|
493
539
|
'RAW',
|
|
494
540
|
'RDICT',
|
|
@@ -525,11 +571,17 @@ module.exports = {
|
|
|
525
571
|
'SESSION_CONTEXT',
|
|
526
572
|
'SESSION_USER',
|
|
527
573
|
'SET',
|
|
574
|
+
'SHORTTEXT',
|
|
528
575
|
'SIBLING',
|
|
576
|
+
'SIGN',
|
|
577
|
+
'SIN',
|
|
578
|
+
'SINH',
|
|
529
579
|
'SMALLDECIMAL',
|
|
530
580
|
'SMALLINT',
|
|
581
|
+
'SNIPPETS',
|
|
531
582
|
'SOME',
|
|
532
583
|
'SQL',
|
|
584
|
+
'SQRT',
|
|
533
585
|
'START',
|
|
534
586
|
'STDDEV',
|
|
535
587
|
'STRING',
|
|
@@ -537,6 +589,7 @@ module.exports = {
|
|
|
537
589
|
'ST_ALPHASHAPEAGGR',
|
|
538
590
|
'ST_ALPHASHAPEAREAAGGR',
|
|
539
591
|
'ST_ALPHASHAPEEDGEAGGR',
|
|
592
|
+
'ST_ASMVT',
|
|
540
593
|
'ST_ASSVGAGGR',
|
|
541
594
|
'ST_CIRCULARSTRING',
|
|
542
595
|
'ST_CLUSTERCELL',
|
|
@@ -552,6 +605,7 @@ module.exports = {
|
|
|
552
605
|
'ST_FROMTEXT',
|
|
553
606
|
'ST_GEOMETRY',
|
|
554
607
|
'ST_GEOMETRYCOLLECTION',
|
|
608
|
+
'ST_GEOMFROMESRIJSON',
|
|
555
609
|
'ST_GEOMFROMEWKB',
|
|
556
610
|
'ST_GEOMFROMEWKT',
|
|
557
611
|
'ST_GEOMFROMGEOHASH',
|
|
@@ -562,6 +616,8 @@ module.exports = {
|
|
|
562
616
|
'ST_INTERSECTIONAGGR',
|
|
563
617
|
'ST_LINESTRING',
|
|
564
618
|
'ST_MAKELINE',
|
|
619
|
+
'ST_MAKEPOLYGON',
|
|
620
|
+
'ST_MEMORY_LOB',
|
|
565
621
|
'ST_MULTILINESTRING',
|
|
566
622
|
'ST_MULTIPOINT',
|
|
567
623
|
'ST_MULTIPOLYGON',
|
|
@@ -586,9 +642,12 @@ module.exports = {
|
|
|
586
642
|
'TABLE',
|
|
587
643
|
'TABLES',
|
|
588
644
|
'TABLESAMPLE',
|
|
645
|
+
'TAN',
|
|
646
|
+
'TANH',
|
|
589
647
|
'TARGET',
|
|
590
648
|
'TEMPORARY',
|
|
591
649
|
'TEXT',
|
|
650
|
+
'TEXT_FILTER',
|
|
592
651
|
'THEN',
|
|
593
652
|
'THREAD',
|
|
594
653
|
'TIME',
|
|
@@ -614,6 +673,7 @@ module.exports = {
|
|
|
614
673
|
'TO_CHAR',
|
|
615
674
|
'TO_CLOB',
|
|
616
675
|
'TO_DATE',
|
|
676
|
+
'TO_DATS',
|
|
617
677
|
'TO_DECIMAL',
|
|
618
678
|
'TO_DOUBLE',
|
|
619
679
|
'TO_INT',
|
|
@@ -642,9 +702,12 @@ module.exports = {
|
|
|
642
702
|
'TRIGGER_UPDATE_COLUMN',
|
|
643
703
|
'TRIM',
|
|
644
704
|
'TRUE',
|
|
705
|
+
'UCASE',
|
|
706
|
+
'UNICODE',
|
|
645
707
|
'UNION',
|
|
646
708
|
'UNKNOWN',
|
|
647
709
|
'UNNEST',
|
|
710
|
+
'UPPER',
|
|
648
711
|
'USER',
|
|
649
712
|
'USING',
|
|
650
713
|
'UTCTIMESTAMP',
|
|
@@ -114,7 +114,7 @@ const centralMessages = {
|
|
|
114
114
|
'ref-undefined-def': { severity: 'Error' },
|
|
115
115
|
'ref-undefined-var': { severity: 'Error' },
|
|
116
116
|
'ref-undefined-element': { severity: 'Error' },
|
|
117
|
-
'ref-unknown-var': { severity: 'Info' },
|
|
117
|
+
'ref-unknown-var': { severity: 'Info', errorFor: [ 'to.hdbcds', 'to.sql', 'to.hdi', 'to.rename' ] },
|
|
118
118
|
'ref-obsolete-parameters': { severity: 'Error', configurableFor: true }, // does not hurt us
|
|
119
119
|
'ref-undefined-param': { severity: 'Error' },
|
|
120
120
|
'ref-rejected-on': { severity: 'Error' },
|
|
@@ -131,6 +131,10 @@ const centralMessages = {
|
|
|
131
131
|
'service-nested-context': { severity: 'Error', configurableFor: true }, // does not hurt compile, TODO
|
|
132
132
|
'service-nested-service': { severity: 'Error', configurableFor: 'deprecated' }, // not supported yet
|
|
133
133
|
|
|
134
|
+
// 'syntax-duplicate-annotate' came late with v3 - make it configurable as
|
|
135
|
+
// fallback, but then parse.cdl is not supposed to work correctly (it can
|
|
136
|
+
// then either issue an error or produce a CSN missing some annotations):
|
|
137
|
+
'syntax-duplicate-annotate': { severity: 'Error', configurableFor: true },
|
|
134
138
|
'syntax-expected-cardinality': { severity: 'Error' },
|
|
135
139
|
'syntax-expected-length': { severity: 'Error' },
|
|
136
140
|
'syntax-expected-translation': { severity: 'Error' },
|
|
@@ -176,6 +180,15 @@ const centralMessages = {
|
|
|
176
180
|
// The keys will be added to `oldNames` of the new message, which is used for reclassification.
|
|
177
181
|
const oldMessageIds = createDict({
|
|
178
182
|
'old-anno-duplicate': 'anno-duplicate', // Example
|
|
183
|
+
|
|
184
|
+
// These IDs are used by large stakeholders. If we change them, we should
|
|
185
|
+
// be backward-compatible.
|
|
186
|
+
// 'redirected-to-complex': 'TODO',
|
|
187
|
+
// 'wildcard-excluding-one': 'TODO',
|
|
188
|
+
// 'wildcard-excluding-many': 'TODO',
|
|
189
|
+
// 'assoc-outside-service': 'TODO',
|
|
190
|
+
// 'redirected-to-same': 'TODO',
|
|
191
|
+
// 'query-navigate-many': 'TODO',
|
|
179
192
|
});
|
|
180
193
|
|
|
181
194
|
// Set up the old-to-new message ID mapping in the message registry.
|
|
@@ -196,8 +209,8 @@ for (const oldName in oldMessageIds) {
|
|
|
196
209
|
// For messageIds, where no text has been provided via code (central def)
|
|
197
210
|
const centralMessageTexts = {
|
|
198
211
|
'api-invalid-option': {
|
|
199
|
-
std: 'Option $(NAME) is
|
|
200
|
-
magicVars: 'Option “magicVars” is
|
|
212
|
+
std: 'Option $(NAME) is no longer supported! Use SNAPI options instead',
|
|
213
|
+
magicVars: 'Option “magicVars” is no longer supported! Use “variableReplacements” instead. See <https://cap.cloud.sap/docs/guides/databases#configuring-variables> for details',
|
|
201
214
|
user: 'Option “variableReplacements” expects “$user” instead of “user”. See <https://cap.cloud.sap/docs/guides/databases#configuring-variables> for details',
|
|
202
215
|
locale: 'Option “variableReplacements” expects “$user.locale” instead of “locale”. See <https://cap.cloud.sap/docs/guides/databases#configuring-variables> for details',
|
|
203
216
|
'noDollar': 'Option “variableReplacements” does not know $(NAME). Did you forget a leading “$”?'
|
|
@@ -219,6 +232,10 @@ const centralMessageTexts = {
|
|
|
219
232
|
'flatten-fkey-exists': 'Generated foreign key element $(NAME) for association $(ART) conflicts with existing element',
|
|
220
233
|
},
|
|
221
234
|
|
|
235
|
+
'syntax-anno-ignored': {
|
|
236
|
+
std: 'Annotations can\'t be used at prefix references',
|
|
237
|
+
doc: 'Doc comments can\'t be used at prefix references',
|
|
238
|
+
},
|
|
222
239
|
'syntax-unexpected-ellipsis': {
|
|
223
240
|
std: 'Expected no more than one $(CODE)',
|
|
224
241
|
'nested-array': 'Unexpected $(CODE) in nested array'
|
|
@@ -267,6 +284,12 @@ const centralMessageTexts = {
|
|
|
267
284
|
unknown: 'Unknown argument $(CODE)',
|
|
268
285
|
duplicate: 'Duplicate argument $(CODE)',
|
|
269
286
|
},
|
|
287
|
+
'syntax-duplicate-annotate': 'You can\'t refer to $(NAME) repeatedly with property $(PROP) in the same annotate statement',
|
|
288
|
+
'syntax-duplicate-extend': {
|
|
289
|
+
std: 'You can\'t define and refer to $(NAME) repeatedly in the same extend statement',
|
|
290
|
+
define: 'You can\'t refer to $(NAME) in the same extend statement where it was defined',
|
|
291
|
+
extend: 'You can\'t refer to $(NAME) repeatedly in the same extend statement',
|
|
292
|
+
},
|
|
270
293
|
'syntax-invalid-literal': {
|
|
271
294
|
'std': 'Invalid literal',
|
|
272
295
|
'uneven-hex': 'A binary literal must have an even number of characters',
|
|
@@ -294,7 +317,7 @@ const centralMessageTexts = {
|
|
|
294
317
|
aspect: 'Element $(ID) has not been found in the anonymous target aspect'
|
|
295
318
|
},
|
|
296
319
|
'ref-unknown-var': {
|
|
297
|
-
std: '
|
|
320
|
+
std: 'No replacement found for special variable $(ID)'
|
|
298
321
|
},
|
|
299
322
|
'ref-unexpected-draft-enabled': 'Composition in draft-enabled entity can\'t lead to another entity with $(ANNO)',
|
|
300
323
|
'ref-rejected-on': {
|
|
@@ -312,6 +335,7 @@ const centralMessageTexts = {
|
|
|
312
335
|
event: 'Unexpected $(KEYWORD) for the type of an event',
|
|
313
336
|
param: 'Unexpected $(KEYWORD) for the type of a parameter definition',
|
|
314
337
|
select: 'Unexpected $(KEYWORD) for type references in queries',
|
|
338
|
+
annotation: '$(KEYWORD) can\'t be used in annotation definitions',
|
|
315
339
|
},
|
|
316
340
|
|
|
317
341
|
'type-missing-argument': 'Missing value for argument $(NAME) in reference to type $(ID)',
|
|
@@ -451,7 +475,11 @@ const centralMessageTexts = {
|
|
|
451
475
|
std: 'Entity can\'t be created due to name collision with existing definition $(NAME)',
|
|
452
476
|
proxy: 'No proxy entity created due to name collision with existing definition $(NAME) of kind $(KIND)'
|
|
453
477
|
},
|
|
454
|
-
'odata-navigation':
|
|
478
|
+
'odata-navigation': {
|
|
479
|
+
std: 'No OData navigation property generated, target $(TARGET) is outside of service $(SERVICE)',
|
|
480
|
+
oncond: 'No OData navigation property generated for association with arbitrary ON condition and target $(TARGET) outside of service $(SERVICE)'
|
|
481
|
+
},
|
|
482
|
+
'odata-parameter-order': 'Unexpected mandatory after optional parameter',
|
|
455
483
|
}
|
|
456
484
|
|
|
457
485
|
/**
|
package/lib/base/messages.js
CHANGED
|
@@ -8,7 +8,6 @@ const { term } = require('../utils/term');
|
|
|
8
8
|
const { locationString } = require('./location');
|
|
9
9
|
const { isDeprecatedEnabled } = require('./model');
|
|
10
10
|
const { centralMessages, centralMessageTexts, oldMessageIds } = require('./message-registry');
|
|
11
|
-
const { copyPropIfExist } = require('../utils/objectUtils');
|
|
12
11
|
const _messageIdsWithExplanation = require('../../share/messages/message-explanations.json').messages;
|
|
13
12
|
const { analyseCsnPath, traverseQuery } = require('../model/csnRefs');
|
|
14
13
|
const { CompilerAssertion } = require("./error");
|
|
@@ -135,7 +134,7 @@ class CompileMessage {
|
|
|
135
134
|
constructor(location, msg, severity = 'Error', id = null, home = null, moduleName = null) {
|
|
136
135
|
this.message = msg;
|
|
137
136
|
this.location = location;
|
|
138
|
-
this.$location =
|
|
137
|
+
this.$location = { ...this.location, address: undefined };
|
|
139
138
|
this.validNames = null;
|
|
140
139
|
if (home) // semantic location, e.g. 'entity:"E"/element:"x"'
|
|
141
140
|
this.home = home;
|
|
@@ -152,33 +151,6 @@ class CompileMessage {
|
|
|
152
151
|
}
|
|
153
152
|
}
|
|
154
153
|
|
|
155
|
-
/**
|
|
156
|
-
* Temporary v1 function to convert an "old-style" location to "new-style".
|
|
157
|
-
*
|
|
158
|
-
* @param {CSN.Location} location
|
|
159
|
-
* @return {CSN.Location}
|
|
160
|
-
* @todo Remove
|
|
161
|
-
*/
|
|
162
|
-
function dollarLocation( location ) {
|
|
163
|
-
const file = location && location.file || undefined;
|
|
164
|
-
if (!file)
|
|
165
|
-
return {};
|
|
166
|
-
const loc = {
|
|
167
|
-
file,
|
|
168
|
-
line: location.line,
|
|
169
|
-
col: location.col,
|
|
170
|
-
address: undefined,
|
|
171
|
-
};
|
|
172
|
-
copyPropIfExist(location, 'endLine', loc);
|
|
173
|
-
copyPropIfExist(location, 'endCol', loc);
|
|
174
|
-
// TODO:
|
|
175
|
-
// return {
|
|
176
|
-
// ...location,
|
|
177
|
-
// address: undefined,
|
|
178
|
-
// };
|
|
179
|
-
return loc;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
154
|
const severitySpecs = {
|
|
183
155
|
error: { name: 'Error', level: 0 },
|
|
184
156
|
warning: { name: 'Warning', level: 1 },
|
|
@@ -257,14 +229,16 @@ function compareSeverities( a, b ) {
|
|
|
257
229
|
}
|
|
258
230
|
|
|
259
231
|
/**
|
|
260
|
-
*
|
|
232
|
+
* Find the nearest $location for the given CSN path in the model.
|
|
233
|
+
* If the path does not exist, the parent is used, and so on.
|
|
234
|
+
*
|
|
261
235
|
* @param {CSN.Model} model
|
|
262
236
|
* @param {CSN.Path} csnPath
|
|
237
|
+
* @returns {CSN.Location | null}
|
|
263
238
|
*/
|
|
264
|
-
function
|
|
239
|
+
function findNearestLocationForPath( model, csnPath ) {
|
|
265
240
|
if (!model)
|
|
266
241
|
return null;
|
|
267
|
-
// Don't display a location if we cannot find one!
|
|
268
242
|
let lastLocation = null;
|
|
269
243
|
/** @type {object} */
|
|
270
244
|
let currentStep = model;
|
|
@@ -435,10 +409,10 @@ function makeMessageFunction( model, options, moduleName = null ) {
|
|
|
435
409
|
// CSN.Location (with line/endLine, col/endCol)
|
|
436
410
|
return [ location, location.home || null, null ]
|
|
437
411
|
|
|
438
|
-
const isCsnPath = (typeof location[0] === 'string');
|
|
412
|
+
const isCsnPath = (typeof location[0] === 'string'); // could be `definitions`, `extensions`, ....
|
|
439
413
|
if (isCsnPath) {
|
|
440
414
|
return [
|
|
441
|
-
|
|
415
|
+
findNearestLocationForPath( model, location ),
|
|
442
416
|
constructSemanticLocationFromCsnPath( location, model ),
|
|
443
417
|
location[1] // location[0] is 'definitions'
|
|
444
418
|
];
|
|
@@ -1086,9 +1060,10 @@ function compareMessageSeverityAware( a, b ) {
|
|
|
1086
1060
|
* @param {CompileMessage} msg
|
|
1087
1061
|
*/
|
|
1088
1062
|
function homeSortName( { home, messageId } ) {
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1063
|
+
if (!home)
|
|
1064
|
+
return (messageId && /^(syntax|api)-/.test( messageId ) ? ' ' + messageId : '~')
|
|
1065
|
+
else
|
|
1066
|
+
return home.substring( home.indexOf(':') ); // i.e. starting with the ':', is always there
|
|
1092
1067
|
}
|
|
1093
1068
|
|
|
1094
1069
|
/**
|
|
@@ -1174,7 +1149,7 @@ function homeName( art, absoluteOnly ) {
|
|
|
1174
1149
|
return null;
|
|
1175
1150
|
else if (art.kind === 'using')
|
|
1176
1151
|
return 'using:' + quoted( art.name.id );
|
|
1177
|
-
else if (art.kind === 'extend')
|
|
1152
|
+
else if (art.kind === 'extend' || art.kind === 'annotate')
|
|
1178
1153
|
return !absoluteOnly && homeNameForExtend ( art );
|
|
1179
1154
|
else if (art.name._artifact) // block, extend, annotate
|
|
1180
1155
|
return homeName( art.name._artifact, absoluteOnly ); // use corresponding definition
|
|
@@ -1189,35 +1164,41 @@ function homeName( art, absoluteOnly ) {
|
|
|
1189
1164
|
// The "home" for extensions is handled differently because `_artifact` is not
|
|
1190
1165
|
// set for unknown extensions and we could have nested extensions.
|
|
1191
1166
|
function homeNameForExtend( art ) {
|
|
1167
|
+
const kind = art.kind || 'extend';
|
|
1192
1168
|
// TODO: fix the following - do like in collectArtifactExtensions() or
|
|
1193
|
-
//
|
|
1194
|
-
const absoluteName =
|
|
1195
|
-
|
|
1169
|
+
// basically resolveUncheckedPath()
|
|
1170
|
+
const absoluteName = art.name.id != null ? art.name.id :
|
|
1171
|
+
(!art.name.element && art.name.absolute || art.name.path && art.name.path.map(s => s && s.id).join('.'));
|
|
1196
1172
|
|
|
1197
1173
|
// Surrounding parent may be another extension.
|
|
1198
1174
|
const parent = art._parent;
|
|
1199
1175
|
if (!parent)
|
|
1200
|
-
return '
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
return artName(parent) + '/' + quoted(absoluteName);
|
|
1206
|
-
|
|
1207
|
-
let extensionName;
|
|
1208
|
-
if (parentArt.enum || parentArt.elements) {
|
|
1209
|
-
const fakeArt = {
|
|
1210
|
-
kind: parentArt.enum ? 'enum' : 'element',
|
|
1211
|
-
name: { element: absoluteName }
|
|
1212
|
-
};
|
|
1213
|
-
extensionName = artName(fakeArt);
|
|
1176
|
+
return kind + ':' + quoted(absoluteName);
|
|
1177
|
+
|
|
1178
|
+
if (art.name.param && parent.params) {
|
|
1179
|
+
const fakeArt = { kind: 'param', name: { param: absoluteName } };
|
|
1180
|
+
return homeNameForExtend(parent) + '/' + artName(fakeArt);
|
|
1214
1181
|
}
|
|
1215
|
-
else {
|
|
1216
|
-
|
|
1182
|
+
else if (art.name.action && parent.actions) {
|
|
1183
|
+
const type = art.name._artifact?.kind || 'action';
|
|
1184
|
+
const fakeArt = { kind: type, name: { action: absoluteName }, _main: art.name._artifact?._main };
|
|
1185
|
+
return homeNameForExtend(parent) + '/' + artName(fakeArt);
|
|
1217
1186
|
}
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1187
|
+
else if (parent.enum || parent.elements || parent.returns?.elements) {
|
|
1188
|
+
// For enum, extensions may store them in `elements`, i.e. don't differ between enum/elements,
|
|
1189
|
+
// so we need to look at the parent artifact.
|
|
1190
|
+
// For `extend <art> with enum`, there is `enum`.
|
|
1191
|
+
const parentArt = parent.name?._artifact;
|
|
1192
|
+
const fakeKind = (parent.enum || parentArt?.enum) ? 'enum' : 'element';
|
|
1193
|
+
const fakeArt = { kind: fakeKind, name: { element: art.name.element } };
|
|
1194
|
+
let parentOfElementChain = parent;
|
|
1195
|
+
while (parentOfElementChain.name?.element && parentOfElementChain._parent)
|
|
1196
|
+
parentOfElementChain = parentOfElementChain._parent;
|
|
1197
|
+
|
|
1198
|
+
return homeNameForExtend(parentOfElementChain) + '/' + artName(fakeArt);
|
|
1199
|
+
}
|
|
1200
|
+
// This case should not happen, but just in case
|
|
1201
|
+
return kind + ':' + artName(parent);
|
|
1221
1202
|
}
|
|
1222
1203
|
|
|
1223
1204
|
function constructSemanticLocationFromCsnPath(csnPath, model) {
|
|
@@ -1230,10 +1211,14 @@ function constructSemanticLocationFromCsnPath(csnPath, model) {
|
|
|
1230
1211
|
];
|
|
1231
1212
|
const queryProps = [ 'from', 'where', 'groupBy', 'having', 'orderBy', 'limit', 'offset' ];
|
|
1232
1213
|
|
|
1233
|
-
|
|
1234
|
-
csnPath
|
|
1235
|
-
|
|
1236
|
-
|
|
1214
|
+
if (csnPath[0] === 'extensions') {
|
|
1215
|
+
const ext = model.extensions && model.extensions[csnPath[1]] || {};
|
|
1216
|
+
if (ext.annotate)
|
|
1217
|
+
return 'annotate:' + quoted(ext.annotate);
|
|
1218
|
+
return 'extend:' + quoted(ext.extend);
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
let { query } = analyseCsnPath(csnPath, model, false);
|
|
1237
1222
|
|
|
1238
1223
|
// remove definitions
|
|
1239
1224
|
csnPath.shift();
|
|
@@ -1373,8 +1358,12 @@ function constructSemanticLocationFromCsnPath(csnPath, model) {
|
|
|
1373
1358
|
if (typeof step === 'number') {
|
|
1374
1359
|
if (currentThing.as)
|
|
1375
1360
|
result += `:${ _quoted(currentThing.as) }`;
|
|
1361
|
+
else if (inRef)
|
|
1362
|
+
result += `:${ _quoted(currentThing) }`;
|
|
1363
|
+
else if (currentThing.ref)
|
|
1364
|
+
result += `:${ _quoted(currentThing.ref.map(r => r.id ? r.id : r).join('.')) }`;
|
|
1376
1365
|
else
|
|
1377
|
-
|
|
1366
|
+
return'';
|
|
1378
1367
|
|
|
1379
1368
|
break;
|
|
1380
1369
|
}
|
package/lib/base/model.js
CHANGED
|
@@ -153,36 +153,67 @@ function createOptionProcessor() {
|
|
|
153
153
|
* Internal: Define a general or command option.
|
|
154
154
|
* Throws if the option is already registered in the given command context.
|
|
155
155
|
* or in the given command.
|
|
156
|
+
*
|
|
156
157
|
* @private
|
|
157
158
|
* @see option()
|
|
158
159
|
*/
|
|
159
160
|
function _addOption(cmd, optString, validValues, options) {
|
|
160
|
-
const
|
|
161
|
-
Object.assign(
|
|
161
|
+
const cliOpt = _parseOptionString(optString, validValues);
|
|
162
|
+
Object.assign(cliOpt, options);
|
|
163
|
+
_addLongOption(cmd, cliOpt.longName, cliOpt);
|
|
164
|
+
_addShortOption(cmd, cliOpt.shortName, cliOpt);
|
|
165
|
+
|
|
166
|
+
for (const alias of cliOpt.aliases || []) {
|
|
167
|
+
const aliasOpt = Object.assign({ }, cliOpt, { isAlias: true });
|
|
168
|
+
_addLongOption(cmd, alias, aliasOpt); // use same camelName, etc. for alias
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return cmd;
|
|
172
|
+
}
|
|
162
173
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
174
|
+
/**
|
|
175
|
+
* Internal: Add longName to the list of options.
|
|
176
|
+
* Throws if the option is already registered in the given command context.
|
|
177
|
+
* or in the given command.
|
|
178
|
+
* `longName` may differ from `opt.longName`, e.g. for aliases.
|
|
179
|
+
*
|
|
180
|
+
* @private
|
|
181
|
+
* @see _addOption()
|
|
182
|
+
*/
|
|
183
|
+
function _addLongOption(cmd, longName, opt) {
|
|
184
|
+
if (cmd.options[longName]) {
|
|
185
|
+
throw new Error(`Duplicate assignment for long option ${longName}`);
|
|
186
|
+
} else if (optionProcessor.options[longName]) {
|
|
166
187
|
// This path is only taken if optString is for commands
|
|
167
188
|
optionProcessor.optionClashes.push({
|
|
168
|
-
option:
|
|
169
|
-
description: `Command '${cmd.longName}' has option clash with general options for: ${
|
|
189
|
+
option: longName,
|
|
190
|
+
description: `Command '${cmd.longName}' has option clash with general options for: ${longName}`
|
|
170
191
|
});
|
|
171
192
|
}
|
|
172
|
-
cmd.options[
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
193
|
+
cmd.options[longName] = opt;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Internal: Add shortName to the list of options.
|
|
197
|
+
* Throws if the option is already registered in the given command context.
|
|
198
|
+
* or in the given command.
|
|
199
|
+
* `longName` may differ from `opt.longName`, e.g. for aliases.
|
|
200
|
+
*
|
|
201
|
+
* @private
|
|
202
|
+
* @see _addOption()
|
|
203
|
+
*/
|
|
204
|
+
function _addShortOption(cmd, shortName, opt) {
|
|
205
|
+
if (!shortName)
|
|
206
|
+
return;
|
|
207
|
+
if (cmd.options[shortName]) {
|
|
208
|
+
throw new Error(`Duplicate assignment for short option ${shortName}`);
|
|
209
|
+
} else if (optionProcessor.options[shortName]) {
|
|
210
|
+
// This path is only taken if optString is for commands
|
|
211
|
+
optionProcessor.optionClashes.push({
|
|
212
|
+
option: shortName,
|
|
213
|
+
description: `Command '${cmd.longName}' has option clash with general options for: ${shortName}`
|
|
214
|
+
});
|
|
184
215
|
}
|
|
185
|
-
|
|
216
|
+
cmd.options[shortName] = opt;
|
|
186
217
|
}
|
|
187
218
|
|
|
188
219
|
// Internal: Parse one command string like "F, toFoo". Return an object like this
|
|
@@ -275,7 +306,8 @@ function createOptionProcessor() {
|
|
|
275
306
|
shortName,
|
|
276
307
|
camelName: camelifyLongOption(longName),
|
|
277
308
|
param,
|
|
278
|
-
validValues
|
|
309
|
+
validValues,
|
|
310
|
+
isAlias: false, // default
|
|
279
311
|
}
|
|
280
312
|
}
|
|
281
313
|
|