@sap/cds-compiler 2.15.8 → 3.1.0
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 +102 -1590
- package/bin/.eslintrc.json +2 -1
- package/bin/cdsc.js +61 -46
- package/doc/API.md +11 -0
- package/doc/CHANGELOG_ARCHIVE.md +1592 -0
- package/doc/CHANGELOG_BETA.md +26 -5
- package/doc/CHANGELOG_DEPRECATED.md +55 -1
- package/doc/{DeprecatedOptions.md → DeprecatedOptions_v2.md} +3 -1
- package/doc/Versioning.md +20 -1
- package/lib/api/.eslintrc.json +2 -2
- package/lib/api/main.js +282 -156
- package/lib/api/options.js +17 -88
- package/lib/api/validate.js +6 -10
- package/lib/base/keywords.js +280 -110
- package/lib/base/message-registry.js +85 -25
- package/lib/base/messages.js +119 -89
- package/lib/base/model.js +46 -2
- package/lib/base/optionProcessorHelper.js +53 -21
- package/lib/checks/actionsFunctions.js +15 -12
- package/lib/checks/annotationsOData.js +1 -1
- package/lib/checks/cdsPersistence.js +1 -0
- package/lib/checks/elements.js +6 -6
- package/lib/checks/invalidTarget.js +1 -1
- package/lib/checks/nonexpandableStructured.js +1 -1
- package/lib/checks/queryNoDbArtifacts.js +2 -1
- package/lib/checks/selectItems.js +101 -15
- package/lib/checks/types.js +7 -8
- package/lib/checks/utils.js +2 -2
- package/lib/checks/validator.js +3 -3
- package/lib/compiler/assert-consistency.js +78 -21
- package/lib/compiler/base.js +6 -4
- package/lib/compiler/builtins.js +177 -10
- package/lib/compiler/checks.js +1 -1
- package/lib/compiler/define.js +28 -23
- package/lib/compiler/extend.js +75 -18
- package/lib/compiler/finalize-parse-cdl.js +25 -18
- package/lib/compiler/index.js +27 -11
- package/lib/compiler/moduleLayers.js +7 -0
- package/lib/compiler/populate.js +26 -39
- package/lib/compiler/propagator.js +12 -7
- package/lib/compiler/resolve.js +207 -236
- package/lib/compiler/shared.js +100 -93
- package/lib/compiler/tweak-assocs.js +13 -20
- package/lib/compiler/utils.js +20 -6
- package/lib/edm/annotations/preprocessAnnotations.js +12 -13
- package/lib/edm/csn2edm.js +35 -37
- 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 +338 -689
- package/lib/edm/edmUtils.js +97 -67
- package/lib/gen/Dictionary.json +29 -9
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +8 -31
- package/lib/gen/language.tokens +105 -114
- package/lib/gen/languageLexer.interp +1 -34
- package/lib/gen/languageLexer.js +892 -1007
- package/lib/gen/languageLexer.tokens +95 -106
- package/lib/gen/languageParser.js +20629 -22474
- 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 +74 -69
- package/lib/json/to-csn.js +17 -14
- package/lib/language/antlrParser.js +2 -2
- package/lib/language/docCommentParser.js +61 -38
- package/lib/language/errorStrategy.js +52 -40
- package/lib/language/genericAntlrParser.js +424 -292
- package/lib/language/language.g4 +604 -687
- package/lib/language/multiLineStringParser.js +14 -42
- package/lib/language/textUtils.js +44 -0
- package/lib/main.d.ts +28 -42
- package/lib/main.js +104 -81
- package/lib/model/api.js +1 -1
- package/lib/model/csnRefs.js +57 -30
- package/lib/model/csnUtils.js +189 -287
- package/lib/model/revealInternalProperties.js +32 -10
- package/lib/model/sortViews.js +32 -31
- package/lib/modelCompare/compare.js +3 -0
- package/lib/optionProcessor.js +91 -57
- package/lib/render/.eslintrc.json +1 -1
- package/lib/render/DuplicateChecker.js +4 -7
- package/lib/render/manageConstraints.js +70 -2
- package/lib/render/toCdl.js +387 -367
- package/lib/render/toHdbcds.js +20 -16
- package/lib/render/toRename.js +44 -22
- package/lib/render/toSql.js +81 -59
- package/lib/render/utils/common.js +16 -3
- package/lib/render/utils/sql.js +20 -19
- package/lib/sql-identifier.js +6 -0
- package/lib/transform/db/.eslintrc.json +3 -2
- package/lib/transform/db/associations.js +43 -35
- package/lib/transform/db/cdsPersistence.js +5 -16
- package/lib/transform/db/constraints.js +1 -1
- package/lib/transform/db/expansion.js +7 -6
- package/lib/transform/db/flattening.js +16 -18
- package/lib/transform/db/transformExists.js +7 -5
- package/lib/transform/db/views.js +3 -3
- package/lib/transform/draft/.eslintrc.json +2 -2
- package/lib/transform/draft/db.js +6 -6
- package/lib/transform/draft/odata.js +6 -7
- package/lib/transform/forHanaNew.js +30 -24
- package/lib/transform/forOdataNew.js +14 -16
- package/lib/transform/localized.js +35 -25
- package/lib/transform/odata/toFinalBaseType.js +10 -10
- package/lib/transform/odata/typesExposure.js +17 -8
- package/lib/transform/odata/utils.js +1 -38
- package/lib/transform/transformUtilsNew.js +63 -77
- package/lib/transform/translateAssocsToJoins.js +2 -2
- package/lib/transform/universalCsn/.eslintrc.json +2 -2
- package/lib/transform/universalCsn/coreComputed.js +11 -6
- package/lib/transform/universalCsn/universalCsnEnricher.js +33 -5
- package/lib/utils/file.js +31 -21
- package/lib/utils/moduleResolve.js +0 -1
- package/lib/utils/timetrace.js +20 -21
- package/package.json +34 -4
- package/share/messages/syntax-expected-integer.md +9 -8
- package/doc/ApiMigration.md +0 -237
- package/doc/CommandLineMigration.md +0 -58
- package/doc/ErrorMessages.md +0 -175
- package/doc/FioriAnnotations.md +0 -94
- package/doc/ODataTransformation.md +0 -273
- package/lib/backends.js +0 -529
- package/lib/checks/unknownMagic.js +0 -41
- package/lib/fix_antlr4-8_warning.js +0 -56
|
@@ -45,6 +45,7 @@ const centralMessages = {
|
|
|
45
45
|
'anno-definition': { severity: 'Warning' },
|
|
46
46
|
'anno-duplicate': { severity: 'Error', configurableFor: true }, // does not hurt us
|
|
47
47
|
'anno-duplicate-unrelated-layer': { severity: 'Error', configurableFor: true }, // does not hurt us
|
|
48
|
+
'anno-unstable-array': { severity: 'Warning' },
|
|
48
49
|
'anno-invalid-sql-element': { severity: 'Error', configurableFor: true }, // @sql.prepend/append - configurable for "I know what I'm doing"
|
|
49
50
|
'anno-invalid-sql-struct': { severity: 'Error', configurableFor: true }, // @sql.prepend/append - configurable for "I know what I'm doing"
|
|
50
51
|
'anno-invalid-sql-kind': { severity: 'Error', configurableFor: true }, // @sql.prepend/append - configurable for "I know what I'm doing"
|
|
@@ -67,7 +68,7 @@ const centralMessages = {
|
|
|
67
68
|
'def-unexpected-calcview-assoc': { severity: 'Error' },
|
|
68
69
|
'chained-array-of': { severity: 'Error' },
|
|
69
70
|
'check-proper-type': { severity: 'Error', configurableFor: [ 'compile' ] },
|
|
70
|
-
'check-proper-type-of': { severity: 'Info', errorFor: [ 'for.odata', 'to.edmx', 'to.hdbcds', 'to.sql', 'to.rename' ] },
|
|
71
|
+
'check-proper-type-of': { severity: 'Info', errorFor: [ 'for.odata', 'to.edmx', 'to.hdbcds', 'to.sql', 'to.hdi', 'to.rename' ] },
|
|
71
72
|
|
|
72
73
|
'expr-no-filter': { severity: 'Error', configurableFor: 'deprecated' },
|
|
73
74
|
|
|
@@ -80,6 +81,7 @@ const centralMessages = {
|
|
|
80
81
|
'expected-type': { severity: 'Error' },
|
|
81
82
|
'ref-sloppy-type': { severity: 'Error' },
|
|
82
83
|
'type-unexpected-typeof': { severity: 'Error', configurableFor: 'deprecated' }, // TODO: make it non-config
|
|
84
|
+
'type-ignoring-argument': { severity: 'Error', configurableFor: true },
|
|
83
85
|
'type-expected-builtin': { severity: 'Error', configurableFor: true },
|
|
84
86
|
'expected-actionparam-type': { severity: 'Error' },
|
|
85
87
|
'ref-sloppy-actionparam-type': { severity: 'Error' },
|
|
@@ -112,10 +114,11 @@ const centralMessages = {
|
|
|
112
114
|
'ref-undefined-def': { severity: 'Error' },
|
|
113
115
|
'ref-undefined-var': { severity: 'Error' },
|
|
114
116
|
'ref-undefined-element': { severity: 'Error' },
|
|
115
|
-
'ref-unknown-var': { severity: 'Info' },
|
|
117
|
+
'ref-unknown-var': { severity: 'Info', errorFor: [ 'to.hdbcds', 'to.sql', 'to.hdi', 'to.rename' ] },
|
|
116
118
|
'ref-obsolete-parameters': { severity: 'Error', configurableFor: true }, // does not hurt us
|
|
117
119
|
'ref-undefined-param': { severity: 'Error' },
|
|
118
120
|
'ref-rejected-on': { severity: 'Error' },
|
|
121
|
+
'ref-expected-element': { severity: 'Error' },
|
|
119
122
|
|
|
120
123
|
'rewrite-key-not-covered-explicit': { severity: 'Error', configurableFor: 'deprecated' },
|
|
121
124
|
'rewrite-key-not-covered-implicit': { severity: 'Error', configurableFor: 'deprecated' },
|
|
@@ -128,14 +131,15 @@ const centralMessages = {
|
|
|
128
131
|
'service-nested-context': { severity: 'Error', configurableFor: true }, // does not hurt compile, TODO
|
|
129
132
|
'service-nested-service': { severity: 'Error', configurableFor: 'deprecated' }, // not supported yet
|
|
130
133
|
|
|
131
|
-
'syntax-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
'syntax-
|
|
135
|
-
'syntax-
|
|
136
|
-
'syntax-
|
|
137
|
-
'syntax-
|
|
138
|
-
'syntax-
|
|
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 },
|
|
138
|
+
'syntax-expected-cardinality': { severity: 'Error' },
|
|
139
|
+
'syntax-expected-length': { severity: 'Error' },
|
|
140
|
+
'syntax-expected-translation': { severity: 'Error' },
|
|
141
|
+
'syntax-required-subproperty': { severity: 'Error' },
|
|
142
|
+
'syntax-unexpected-property': { severity: 'Error', configurableFor: true }, // is the removed
|
|
139
143
|
'syntax-deprecated-ident': { severity: 'Error', configurableFor: true },
|
|
140
144
|
'syntax-fragile-alias': { severity: 'Error', configurableFor: true },
|
|
141
145
|
'syntax-fragile-ident': { severity: 'Error', configurableFor: true },
|
|
@@ -148,6 +152,8 @@ const centralMessages = {
|
|
|
148
152
|
'syntax-missing-escape': { severity: 'Error' },
|
|
149
153
|
|
|
150
154
|
'syntax-expected-integer': { severity: 'Error' },
|
|
155
|
+
'syntax-invalid-masked': { severity: 'Error', configurableFor: true },
|
|
156
|
+
'syntax-unexpected-null': { severity: 'Error', configurableFor: true },
|
|
151
157
|
|
|
152
158
|
'type-managed-composition': { severity: 'Error', configurableFor: 'deprecated' }, // TODO: non-config
|
|
153
159
|
|
|
@@ -174,6 +180,15 @@ const centralMessages = {
|
|
|
174
180
|
// The keys will be added to `oldNames` of the new message, which is used for reclassification.
|
|
175
181
|
const oldMessageIds = createDict({
|
|
176
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',
|
|
177
192
|
});
|
|
178
193
|
|
|
179
194
|
// Set up the old-to-new message ID mapping in the message registry.
|
|
@@ -194,34 +209,50 @@ for (const oldName in oldMessageIds) {
|
|
|
194
209
|
// For messageIds, where no text has been provided via code (central def)
|
|
195
210
|
const centralMessageTexts = {
|
|
196
211
|
'api-invalid-option': {
|
|
197
|
-
std: 'Option $(NAME) is
|
|
198
|
-
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',
|
|
199
214
|
user: 'Option “variableReplacements” expects “$user” instead of “user”. See <https://cap.cloud.sap/docs/guides/databases#configuring-variables> for details',
|
|
200
215
|
locale: 'Option “variableReplacements” expects “$user.locale” instead of “locale”. See <https://cap.cloud.sap/docs/guides/databases#configuring-variables> for details',
|
|
201
216
|
'noDollar': 'Option “variableReplacements” does not know $(NAME). Did you forget a leading “$”?'
|
|
202
217
|
},
|
|
203
218
|
|
|
204
219
|
'anno-duplicate': 'Duplicate assignment with $(ANNO)',
|
|
220
|
+
'anno-duplicate-unrelated-layer': 'Duplicate assignment with $(ANNO)',
|
|
221
|
+
'anno-unstable-array': 'Unstable order of array items due to repeated assignments for $(ANNO) in unrelated layers',
|
|
205
222
|
'anno-mismatched-ellipsis': 'An array with $(CODE) can only be used if there is an assignment below with an array value',
|
|
206
223
|
'anno-unexpected-ellipsis': 'No base annotation available to apply $(CODE)',
|
|
207
224
|
'anno-unexpected-ellipsis-layers': 'No base annotation available to apply $(CODE)',
|
|
208
225
|
'chained-array-of': '"Array of"/"many" must not be chained with another "array of"/"many" inside a service',
|
|
209
|
-
|
|
210
|
-
'
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
226
|
+
|
|
227
|
+
'name-duplicate-element': {
|
|
228
|
+
'std': 'Generated element $(NAME) conflicts with another element',
|
|
229
|
+
'flatten-element-gen': 'Generated element $(NAME) conflicts with other generated element',
|
|
230
|
+
'flatten-element-exist': 'Flattened name of structured element conflicts with existing element $(NAME)',
|
|
231
|
+
'flatten-fkey-gen': 'Duplicate definition of foreign key element $(NAME) for association $(ART)',
|
|
232
|
+
'flatten-fkey-exists': 'Generated foreign key element $(NAME) for association $(ART) conflicts with existing element',
|
|
233
|
+
},
|
|
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
|
+
},
|
|
239
|
+
'syntax-unexpected-ellipsis': {
|
|
240
|
+
std: 'Expected no more than one $(CODE)',
|
|
241
|
+
'nested-array': 'Unexpected $(CODE) in nested array'
|
|
242
|
+
},
|
|
243
|
+
'syntax-expected-object': 'Expected object for property $(PROP)',
|
|
244
|
+
'syntax-expected-column': 'Expected object or string \'*\' for property $(PROP)',
|
|
245
|
+
'syntax-expected-natnum': 'Expected non-negative number for property $(PROP)',
|
|
246
|
+
'syntax-expected-cardinality': 'Expected non-negative number or string \'*\' for property $(PROP)',
|
|
247
|
+
'syntax-expected-reference': 'Expected non-empty string or object for property $(PROP)',
|
|
248
|
+
'syntax-expected-term': 'Expected non-empty string or object for property $(PROP)',
|
|
218
249
|
'syntax-dollar-ident': {
|
|
219
250
|
std: 'An artifact starting with $(NAME) might shadow a special variable - replace by another name',
|
|
220
251
|
$tableAlias: 'A table alias name starting with $(NAME) might shadow a special variable - replace by another name',
|
|
221
252
|
$tableImplicit: 'The resulting table alias starts with $(NAME) and might shadow a special variable - specify another name with $(KEYWORD)',
|
|
222
253
|
mixin: 'A mixin name starting with $(NAME) might shadow a special variable - replace by another name' ,
|
|
223
254
|
},
|
|
224
|
-
'syntax-
|
|
255
|
+
'syntax-expected-length': {
|
|
225
256
|
std: 'Expected array in $(PROP) to have at least $(N) items',
|
|
226
257
|
one: 'Expected array in $(PROP) to have at least one item',
|
|
227
258
|
suffix: 'With sibling property $(OTHERPROP), expected array in $(PROP) to have at least one item',
|
|
@@ -253,6 +284,26 @@ const centralMessageTexts = {
|
|
|
253
284
|
unknown: 'Unknown argument $(CODE)',
|
|
254
285
|
duplicate: 'Duplicate argument $(CODE)',
|
|
255
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
|
+
},
|
|
293
|
+
'syntax-invalid-literal': {
|
|
294
|
+
'std': 'Invalid literal',
|
|
295
|
+
'uneven-hex': 'A binary literal must have an even number of characters',
|
|
296
|
+
'invalid-hex': 'A binary literal must only contain characters 0-9, a-f and A-F',
|
|
297
|
+
'time': 'Expected time\'hh:mm:ss\' where hh, mm and the optional ss are numbers',
|
|
298
|
+
'date': 'Expected date\'YYYY-MM-DD\' where YYYY, MM and DD are numbers',
|
|
299
|
+
'timestamp': 'Expected timestamp\'YYYY-MM-DD hh:mm:ss.u…u\' where YYYY, MM, DD, hh, mm, ss and u are numbers (optional 1-7×u)',
|
|
300
|
+
},
|
|
301
|
+
'syntax-unexpected-null': 'Keyword $(KEYWORD) must appear after the enum definition and not before',
|
|
302
|
+
'syntax-unexpected-vocabulary': {
|
|
303
|
+
std: 'Annotations can\'t be defined inside contexts or services',
|
|
304
|
+
service: 'Annotations can\'t be defined inside services',
|
|
305
|
+
context: 'Annotations can\'t be defined inside contexts',
|
|
306
|
+
},
|
|
256
307
|
'ref-undefined-def': {
|
|
257
308
|
std: 'Artifact $(ART) has not been found',
|
|
258
309
|
// TODO: proposal 'No definition of $(NAME) found',
|
|
@@ -266,7 +317,7 @@ const centralMessageTexts = {
|
|
|
266
317
|
aspect: 'Element $(ID) has not been found in the anonymous target aspect'
|
|
267
318
|
},
|
|
268
319
|
'ref-unknown-var': {
|
|
269
|
-
std: '
|
|
320
|
+
std: 'No replacement found for special variable $(ID)'
|
|
270
321
|
},
|
|
271
322
|
'ref-unexpected-draft-enabled': 'Composition in draft-enabled entity can\'t lead to another entity with $(ANNO)',
|
|
272
323
|
'ref-rejected-on': {
|
|
@@ -274,12 +325,17 @@ const centralMessageTexts = {
|
|
|
274
325
|
mixin: 'Do not refer to a mixin like $(ID) in the explicit ON of a redirection',
|
|
275
326
|
alias: 'Do not refer to a source element (via table alias $(ID)) in the explicit ON of a redirection',
|
|
276
327
|
},
|
|
328
|
+
'ref-expected-element': {
|
|
329
|
+
std: 'Expected element reference',
|
|
330
|
+
magicVar: 'Only elements of magic variable $(ID) can be selected',
|
|
331
|
+
},
|
|
277
332
|
'type-unexpected-typeof': {
|
|
278
333
|
std: 'Unexpected $(KEYWORD) for the type reference here',
|
|
279
334
|
type: 'Unexpected $(KEYWORD) in type of a type definition',
|
|
280
335
|
event: 'Unexpected $(KEYWORD) for the type of an event',
|
|
281
336
|
param: 'Unexpected $(KEYWORD) for the type of a parameter definition',
|
|
282
337
|
select: 'Unexpected $(KEYWORD) for type references in queries',
|
|
338
|
+
annotation: '$(KEYWORD) can\'t be used in annotation definitions',
|
|
283
339
|
},
|
|
284
340
|
|
|
285
341
|
'type-missing-argument': 'Missing value for argument $(NAME) in reference to type $(ID)',
|
|
@@ -419,7 +475,11 @@ const centralMessageTexts = {
|
|
|
419
475
|
std: 'Entity can\'t be created due to name collision with existing definition $(NAME)',
|
|
420
476
|
proxy: 'No proxy entity created due to name collision with existing definition $(NAME) of kind $(KIND)'
|
|
421
477
|
},
|
|
422
|
-
'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',
|
|
423
483
|
}
|
|
424
484
|
|
|
425
485
|
/**
|
|
@@ -431,7 +491,7 @@ const centralMessageTexts = {
|
|
|
431
491
|
* Whether the error can be reclassified to a warning or lower.
|
|
432
492
|
* If not `true` then an array is expected with specified modules in which the error is downgradable.
|
|
433
493
|
* Only has an effect if default severity is 'Error'.
|
|
434
|
-
* 'deprecated': severity can only be changed with deprecated.
|
|
494
|
+
* 'deprecated': severity can only be changed with deprecated._downgradableErrors.
|
|
435
495
|
* TODO: Value `true` is temporary. Use an array instead.
|
|
436
496
|
* @property {string[]} [errorFor] Array of module names where the message shall be reclassified to an error.
|
|
437
497
|
* @property {boolean} [throughMessageCall]
|
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");
|
|
@@ -27,7 +26,7 @@ let test$texts = null;
|
|
|
27
26
|
/**
|
|
28
27
|
* Returns true if at least one of the given messages is of severity "Error".
|
|
29
28
|
*
|
|
30
|
-
* @param {
|
|
29
|
+
* @param {CompileMessage[]} messages
|
|
31
30
|
* @returns {boolean}
|
|
32
31
|
*/
|
|
33
32
|
function hasErrors( messages ) {
|
|
@@ -39,7 +38,7 @@ function hasErrors( messages ) {
|
|
|
39
38
|
* and *cannot* be reclassified to a warning for the given module.
|
|
40
39
|
* Won't detect already downgraded messages.
|
|
41
40
|
*
|
|
42
|
-
* @param {
|
|
41
|
+
* @param {CompileMessage[]} messages
|
|
43
42
|
* @param {string} moduleName
|
|
44
43
|
* @returns {boolean}
|
|
45
44
|
*/
|
|
@@ -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;
|
|
@@ -319,20 +293,23 @@ function createMessageFunctions( options, moduleName, model = null ) {
|
|
|
319
293
|
* ```
|
|
320
294
|
* @param {object} model
|
|
321
295
|
* @param {CSN.Options} [options]
|
|
322
|
-
* @param {string} [moduleName]
|
|
296
|
+
* @param {string|null} [moduleName]
|
|
323
297
|
*/
|
|
324
298
|
function makeMessageFunction( model, options, moduleName = null ) {
|
|
325
|
-
|
|
326
|
-
|
|
299
|
+
if (options.testMode) {
|
|
300
|
+
// ensure message consistency during runtime with --test-mode
|
|
327
301
|
_check$Init( options );
|
|
302
|
+
if (!options.messages)
|
|
303
|
+
throw new CompilerAssertion('makeMessageFunction() expects options.messages to exist in testMode!');
|
|
304
|
+
}
|
|
328
305
|
|
|
329
306
|
const hasMessageArray = !!options.messages;
|
|
330
|
-
const deprecatedDowngradable = isDeprecatedEnabled( options, '
|
|
307
|
+
const deprecatedDowngradable = isDeprecatedEnabled( options, '_downgradableErrors' );
|
|
331
308
|
/**
|
|
332
309
|
* Array of collected compiler messages. Only use it for debugging. Will not
|
|
333
310
|
* contain the messages created during a `callTransparently` call.
|
|
334
311
|
*
|
|
335
|
-
* @type {
|
|
312
|
+
* @type {CompileMessage[]}
|
|
336
313
|
*/
|
|
337
314
|
let messages = options.messages || [];
|
|
338
315
|
/**
|
|
@@ -361,7 +338,7 @@ function makeMessageFunction( model, options, moduleName = null ) {
|
|
|
361
338
|
const [ fileLocation, semanticLocation, definition ] = _normalizeMessageLocation(location);
|
|
362
339
|
const text = messageText( texts || centralMessageTexts[id], textOrArguments );
|
|
363
340
|
|
|
364
|
-
/** @type {
|
|
341
|
+
/** @type {CompileMessage} */
|
|
365
342
|
const msg = new CompileMessage( fileLocation, text, severity, id, semanticLocation, moduleName );
|
|
366
343
|
if (options.internalMsg)
|
|
367
344
|
msg.error = new Error( 'stack' );
|
|
@@ -432,10 +409,10 @@ function makeMessageFunction( model, options, moduleName = null ) {
|
|
|
432
409
|
// CSN.Location (with line/endLine, col/endCol)
|
|
433
410
|
return [ location, location.home || null, null ]
|
|
434
411
|
|
|
435
|
-
const isCsnPath = (typeof location[0] === 'string');
|
|
412
|
+
const isCsnPath = (typeof location[0] === 'string'); // could be `definitions`, `extensions`, ....
|
|
436
413
|
if (isCsnPath) {
|
|
437
414
|
return [
|
|
438
|
-
|
|
415
|
+
findNearestLocationForPath( model, location ),
|
|
439
416
|
constructSemanticLocationFromCsnPath( location, model ),
|
|
440
417
|
location[1] // location[0] is 'definitions'
|
|
441
418
|
];
|
|
@@ -553,7 +530,7 @@ function makeMessageFunction( model, options, moduleName = null ) {
|
|
|
553
530
|
*
|
|
554
531
|
* @param {Function} callback
|
|
555
532
|
* @param {...any} args
|
|
556
|
-
* @returns {
|
|
533
|
+
* @returns {CompileMessage[]}
|
|
557
534
|
*/
|
|
558
535
|
function callTransparently(callback, ...args) {
|
|
559
536
|
const backup = messages;
|
|
@@ -579,6 +556,22 @@ function _check$Init( options ) {
|
|
|
579
556
|
}
|
|
580
557
|
}
|
|
581
558
|
|
|
559
|
+
/**
|
|
560
|
+
* Check the consistency of the given message and run some basic lint checks. These include:
|
|
561
|
+
*
|
|
562
|
+
* - Long message IDs must be listed centrally.
|
|
563
|
+
* - Messages with the same ID must have the same severity (in a module).
|
|
564
|
+
* - Messages with the same ID must have the same message texts.
|
|
565
|
+
* This ensures that $(PLACEHOLDERS) are used and that we don't accidentally
|
|
566
|
+
* use the same ID for different meanings, i.e. texts.
|
|
567
|
+
*
|
|
568
|
+
* @param {string} id
|
|
569
|
+
* @param {string} moduleName
|
|
570
|
+
* @param {string} severity
|
|
571
|
+
* @param {string|object} texts
|
|
572
|
+
* @param {CSN.Options} options
|
|
573
|
+
* @private
|
|
574
|
+
*/
|
|
582
575
|
function _check$Consistency( id, moduleName, severity, texts, options ) {
|
|
583
576
|
if (id.length > 30 && !centralMessages[id])
|
|
584
577
|
throw new CompilerAssertion( `The message ID "${id}" has more than 30 chars and must be listed centrally` );
|
|
@@ -589,6 +582,16 @@ function _check$Consistency( id, moduleName, severity, texts, options ) {
|
|
|
589
582
|
_check$Texts( id, variant, text );
|
|
590
583
|
}
|
|
591
584
|
|
|
585
|
+
/**
|
|
586
|
+
* Check the consistency of the message severity for the given message ID.
|
|
587
|
+
* Messages with the same ID must have the same severity (in a module).
|
|
588
|
+
* Non-downgradable errors must never be called with a lower severity.
|
|
589
|
+
*
|
|
590
|
+
* @param {string} id
|
|
591
|
+
* @param {string} moduleName
|
|
592
|
+
* @param {string} severity
|
|
593
|
+
* @private
|
|
594
|
+
*/
|
|
592
595
|
function _check$Severities( id, moduleName, severity ) {
|
|
593
596
|
if (!severity) // if just used message(), we are automatically consistent
|
|
594
597
|
return;
|
|
@@ -598,22 +601,34 @@ function _check$Severities( id, moduleName, severity ) {
|
|
|
598
601
|
if (!expected)
|
|
599
602
|
test$severities[id] = severity;
|
|
600
603
|
else if (expected !== severity)
|
|
601
|
-
throw new CompilerAssertion( `
|
|
604
|
+
throw new CompilerAssertion( `Inconsistent severity: Expecting "${expected}" from previous call, not "${severity}" for message ID "${id}"` );
|
|
602
605
|
return;
|
|
603
606
|
}
|
|
604
607
|
// now try whether the message could be something less than an Error in the module due to user wishes
|
|
605
608
|
if (!isDowngradable( id, moduleName )) { // always an error in module
|
|
606
609
|
if (severity !== 'Error')
|
|
607
|
-
throw new CompilerAssertion( `
|
|
610
|
+
throw new CompilerAssertion( `Inconsistent severity: Expecting "Error", not "${severity}" for message ID "${id}" in module "${moduleName}"` );
|
|
608
611
|
}
|
|
609
612
|
else if (spec.severity === 'Error') {
|
|
610
|
-
throw new CompilerAssertion( `Expecting the use of function message() when message ID "${id}" is a configurable error in module "${moduleName}"` );
|
|
613
|
+
throw new CompilerAssertion( `Inconsistent severity: Expecting the use of function message() when message ID "${id}" is a configurable error in module "${moduleName}"` );
|
|
611
614
|
}
|
|
612
615
|
else if (spec.severity !== severity) {
|
|
613
|
-
throw new CompilerAssertion( `
|
|
616
|
+
throw new CompilerAssertion( `Inconsistent severity: Expecting "${spec.severity}", not "${severity}" for message ID "${id}" in module "${moduleName}"` );
|
|
614
617
|
}
|
|
615
618
|
}
|
|
616
619
|
|
|
620
|
+
/**
|
|
621
|
+
* Check the consistency of the message text for the given message ID.
|
|
622
|
+
*
|
|
623
|
+
* Messages with the same ID must have the same message texts.
|
|
624
|
+
* This ensures that $(PLACEHOLDERS) are used and that we don't accidentally
|
|
625
|
+
* use the same ID for different meanings, i.e. texts.
|
|
626
|
+
*
|
|
627
|
+
* @param {string} id
|
|
628
|
+
* @param {string} prop
|
|
629
|
+
* @param {string} value
|
|
630
|
+
* @private
|
|
631
|
+
*/
|
|
617
632
|
function _check$Texts( id, prop, value ) {
|
|
618
633
|
if (!test$texts[id])
|
|
619
634
|
test$texts[id] = Object.create(null);
|
|
@@ -621,7 +636,7 @@ function _check$Texts( id, prop, value ) {
|
|
|
621
636
|
if (!expected)
|
|
622
637
|
test$texts[id][prop] = value;
|
|
623
638
|
else if (expected !== value)
|
|
624
|
-
throw new CompilerAssertion( `Expecting
|
|
639
|
+
throw new CompilerAssertion( `Different texts for the same message ID. Expecting "${expected}", not "${value}" for ID "${id}" and text variant "${prop}"`);
|
|
625
640
|
}
|
|
626
641
|
|
|
627
642
|
const quote = { // could be an option in the future
|
|
@@ -819,7 +834,7 @@ function weakLocation( loc ) {
|
|
|
819
834
|
* Example:
|
|
820
835
|
* <source>.cds:3:11: Error message-id: Can't find type `nu` in this scope (in entity:“E”/element:“e”)
|
|
821
836
|
*
|
|
822
|
-
* @param {
|
|
837
|
+
* @param {CompileMessage} err
|
|
823
838
|
* @param {boolean} [normalizeFilename]
|
|
824
839
|
* @param {boolean} [noMessageId]
|
|
825
840
|
* @param {boolean} [noHome]
|
|
@@ -841,7 +856,7 @@ function messageString( err, normalizeFilename, noMessageId, noHome ) {
|
|
|
841
856
|
* Return message hash which is either the message string without the file location,
|
|
842
857
|
* or the full message string if no semantic location is provided.
|
|
843
858
|
*
|
|
844
|
-
* @param {
|
|
859
|
+
* @param {CompileMessage} msg
|
|
845
860
|
* @returns {string} can be used to uniquely identify a message
|
|
846
861
|
*/
|
|
847
862
|
function messageHash(msg) {
|
|
@@ -867,7 +882,7 @@ function messageHash(msg) {
|
|
|
867
882
|
* <source>.cds:3:11, at entity:“E”/element:“e”
|
|
868
883
|
* ```
|
|
869
884
|
*
|
|
870
|
-
* @param {
|
|
885
|
+
* @param {CompileMessage} err
|
|
871
886
|
* @param {object} [config = {}]
|
|
872
887
|
* @param {boolean} [config.normalizeFilename] Replace windows `\` with forward slashes `/`.
|
|
873
888
|
* @param {boolean} [config.noMessageId]
|
|
@@ -915,7 +930,7 @@ function messageStringMultiline( err, config = {} ) {
|
|
|
915
930
|
*
|
|
916
931
|
* @param {string[]} sourceLines The source code split up into lines, e.g. by `splitLines(src)`
|
|
917
932
|
* from `lib/utils/file.js`
|
|
918
|
-
* @param {
|
|
933
|
+
* @param {CompileMessage} err Error object containing all details like line, message, etc.
|
|
919
934
|
* @param {object} [config = {}]
|
|
920
935
|
* @param {boolean | 'auto'} [config.color] If true, ANSI escape codes will be used for coloring the `^`. If false, no
|
|
921
936
|
* coloring will be used. If 'auto', we will decide based on certain factors such
|
|
@@ -994,8 +1009,8 @@ function messageContext(sourceLines, err, config) {
|
|
|
994
1009
|
* larger than `b`, and -1 if `a` is smaller than `b`. Messages without a location
|
|
995
1010
|
* are considered larger than messages with a location.
|
|
996
1011
|
*
|
|
997
|
-
* @param {
|
|
998
|
-
* @param {
|
|
1012
|
+
* @param {CompileMessage} a
|
|
1013
|
+
* @param {CompileMessage} b
|
|
999
1014
|
*/
|
|
1000
1015
|
function compareMessage( a, b ) {
|
|
1001
1016
|
const aFile = a.$location && a.$location.file;
|
|
@@ -1029,8 +1044,8 @@ function compareMessage( a, b ) {
|
|
|
1029
1044
|
* location and severity, >0 if `a` is larger than `b`, and <0 if `a` is smaller
|
|
1030
1045
|
* than `b`. See `compareSeverities()` for how severities are compared.
|
|
1031
1046
|
*
|
|
1032
|
-
* @param {
|
|
1033
|
-
* @param {
|
|
1047
|
+
* @param {CompileMessage} a
|
|
1048
|
+
* @param {CompileMessage} b
|
|
1034
1049
|
*/
|
|
1035
1050
|
function compareMessageSeverityAware( a, b ) {
|
|
1036
1051
|
const c = compareSeverities(a.severity, b.severity);
|
|
@@ -1042,12 +1057,13 @@ function compareMessageSeverityAware( a, b ) {
|
|
|
1042
1057
|
* Messages without semantic locations are considered smaller (for syntax errors)
|
|
1043
1058
|
* and (currently - should not happen in v2) larger for other messages.
|
|
1044
1059
|
*
|
|
1045
|
-
* @param {
|
|
1060
|
+
* @param {CompileMessage} msg
|
|
1046
1061
|
*/
|
|
1047
1062
|
function homeSortName( { home, messageId } ) {
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
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
|
|
1051
1067
|
}
|
|
1052
1068
|
|
|
1053
1069
|
/**
|
|
@@ -1061,7 +1077,7 @@ function homeSortName( { home, messageId } ) {
|
|
|
1061
1077
|
* A message is more precise if it is contained in the other or if
|
|
1062
1078
|
* the first does not have an endLine/endCol.
|
|
1063
1079
|
*
|
|
1064
|
-
* @param {
|
|
1080
|
+
* @param {CompileMessage[]} messages
|
|
1065
1081
|
*/
|
|
1066
1082
|
function deduplicateMessages( messages ) {
|
|
1067
1083
|
const seen = new Map();
|
|
@@ -1133,7 +1149,7 @@ function homeName( art, absoluteOnly ) {
|
|
|
1133
1149
|
return null;
|
|
1134
1150
|
else if (art.kind === 'using')
|
|
1135
1151
|
return 'using:' + quoted( art.name.id );
|
|
1136
|
-
else if (art.kind === 'extend')
|
|
1152
|
+
else if (art.kind === 'extend' || art.kind === 'annotate')
|
|
1137
1153
|
return !absoluteOnly && homeNameForExtend ( art );
|
|
1138
1154
|
else if (art.name._artifact) // block, extend, annotate
|
|
1139
1155
|
return homeName( art.name._artifact, absoluteOnly ); // use corresponding definition
|
|
@@ -1148,35 +1164,41 @@ function homeName( art, absoluteOnly ) {
|
|
|
1148
1164
|
// The "home" for extensions is handled differently because `_artifact` is not
|
|
1149
1165
|
// set for unknown extensions and we could have nested extensions.
|
|
1150
1166
|
function homeNameForExtend( art ) {
|
|
1167
|
+
const kind = art.kind || 'extend';
|
|
1151
1168
|
// TODO: fix the following - do like in collectArtifactExtensions() or
|
|
1152
|
-
//
|
|
1153
|
-
const absoluteName =
|
|
1154
|
-
|
|
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('.'));
|
|
1155
1172
|
|
|
1156
1173
|
// Surrounding parent may be another extension.
|
|
1157
1174
|
const parent = art._parent;
|
|
1158
1175
|
if (!parent)
|
|
1159
|
-
return '
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
return artName(parent) + '/' + quoted(absoluteName);
|
|
1165
|
-
|
|
1166
|
-
let extensionName;
|
|
1167
|
-
if (parentArt.enum || parentArt.elements) {
|
|
1168
|
-
const fakeArt = {
|
|
1169
|
-
kind: parentArt.enum ? 'enum' : 'element',
|
|
1170
|
-
name: { element: absoluteName }
|
|
1171
|
-
};
|
|
1172
|
-
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);
|
|
1173
1181
|
}
|
|
1174
|
-
else {
|
|
1175
|
-
|
|
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);
|
|
1176
1186
|
}
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
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);
|
|
1180
1202
|
}
|
|
1181
1203
|
|
|
1182
1204
|
function constructSemanticLocationFromCsnPath(csnPath, model) {
|
|
@@ -1189,10 +1211,14 @@ function constructSemanticLocationFromCsnPath(csnPath, model) {
|
|
|
1189
1211
|
];
|
|
1190
1212
|
const queryProps = [ 'from', 'where', 'groupBy', 'having', 'orderBy', 'limit', 'offset' ];
|
|
1191
1213
|
|
|
1192
|
-
|
|
1193
|
-
csnPath
|
|
1194
|
-
|
|
1195
|
-
|
|
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);
|
|
1196
1222
|
|
|
1197
1223
|
// remove definitions
|
|
1198
1224
|
csnPath.shift();
|
|
@@ -1332,8 +1358,12 @@ function constructSemanticLocationFromCsnPath(csnPath, model) {
|
|
|
1332
1358
|
if (typeof step === 'number') {
|
|
1333
1359
|
if (currentThing.as)
|
|
1334
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('.')) }`;
|
|
1335
1365
|
else
|
|
1336
|
-
|
|
1366
|
+
return'';
|
|
1337
1367
|
|
|
1338
1368
|
break;
|
|
1339
1369
|
}
|