@sap/cds-compiler 2.11.2 → 2.13.6
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 +175 -2
- package/bin/.eslintrc.json +1 -2
- package/bin/cds_update_identifiers.js +10 -8
- package/bin/cdsc.js +23 -17
- package/bin/cdsse.js +2 -2
- package/bin/cdsv2m.js +3 -2
- package/doc/CHANGELOG_ARCHIVE.md +1 -1
- package/doc/CHANGELOG_BETA.md +25 -6
- package/doc/CHANGELOG_DEPRECATED.md +22 -6
- package/doc/NameResolution.md +21 -16
- package/lib/api/main.js +32 -79
- package/lib/api/options.js +3 -2
- package/lib/api/validate.js +2 -1
- package/lib/backends.js +16 -26
- package/lib/base/dictionaries.js +0 -8
- package/lib/base/error.js +26 -0
- package/lib/base/keywords.js +10 -19
- package/lib/base/location.js +9 -4
- package/lib/base/message-registry.js +75 -9
- package/lib/base/messages.js +31 -35
- package/lib/base/model.js +2 -62
- package/lib/base/optionProcessorHelper.js +246 -183
- package/lib/checks/.eslintrc.json +2 -0
- package/lib/checks/actionsFunctions.js +2 -1
- package/lib/checks/annotationsOData.js +1 -1
- package/lib/checks/cdsPersistence.js +2 -1
- package/lib/checks/emptyOrOnlyVirtual.js +2 -2
- package/lib/checks/enricher.js +17 -1
- package/lib/checks/foreignKeys.js +4 -4
- package/lib/checks/invalidTarget.js +3 -1
- package/lib/checks/managedInType.js +4 -4
- package/lib/checks/managedWithoutKeys.js +3 -1
- package/lib/checks/queryNoDbArtifacts.js +1 -3
- package/lib/checks/selectItems.js +4 -4
- package/lib/checks/sql-snippets.js +94 -0
- package/lib/checks/types.js +1 -1
- package/lib/checks/unknownMagic.js +1 -1
- package/lib/checks/validator.js +12 -7
- package/lib/compiler/assert-consistency.js +12 -8
- package/lib/compiler/base.js +0 -1
- package/lib/compiler/builtins.js +42 -21
- package/lib/compiler/checks.js +46 -12
- package/lib/compiler/cycle-detector.js +1 -1
- package/lib/compiler/define.js +1103 -0
- package/lib/compiler/extend.js +983 -0
- package/lib/compiler/finalize-parse-cdl.js +231 -0
- package/lib/compiler/index.js +46 -39
- package/lib/compiler/kick-start.js +190 -0
- package/lib/compiler/moduleLayers.js +4 -4
- package/lib/compiler/populate.js +1226 -0
- package/lib/compiler/propagator.js +113 -47
- package/lib/compiler/resolve.js +1433 -0
- package/lib/compiler/shared.js +100 -65
- package/lib/compiler/tweak-assocs.js +529 -0
- package/lib/compiler/utils.js +215 -33
- package/lib/edm/.eslintrc.json +5 -0
- package/lib/edm/annotations/genericTranslation.js +38 -25
- package/lib/edm/annotations/preprocessAnnotations.js +3 -3
- package/lib/edm/csn2edm.js +10 -9
- package/lib/edm/edm.js +19 -20
- package/lib/edm/edmPreprocessor.js +166 -95
- package/lib/edm/edmUtils.js +127 -34
- package/lib/gen/Dictionary.json +92 -43
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +11 -1
- package/lib/gen/language.tokens +86 -82
- package/lib/gen/languageLexer.interp +18 -1
- package/lib/gen/languageLexer.js +925 -847
- package/lib/gen/languageLexer.tokens +78 -74
- package/lib/gen/languageParser.js +5434 -4298
- package/lib/json/from-csn.js +59 -17
- package/lib/json/to-csn.js +189 -71
- package/lib/language/antlrParser.js +3 -3
- package/lib/language/docCommentParser.js +3 -3
- package/lib/language/errorStrategy.js +26 -8
- package/lib/language/genericAntlrParser.js +144 -53
- package/lib/language/language.g4 +424 -200
- package/lib/language/multiLineStringParser.js +536 -0
- package/lib/main.d.ts +550 -61
- package/lib/main.js +38 -11
- package/lib/model/api.js +3 -1
- package/lib/model/csnRefs.js +322 -198
- package/lib/model/csnUtils.js +226 -370
- package/lib/model/enrichCsn.js +124 -69
- package/lib/model/revealInternalProperties.js +29 -7
- package/lib/model/sortViews.js +10 -2
- package/lib/modelCompare/compare.js +17 -12
- package/lib/optionProcessor.js +8 -3
- package/lib/render/.eslintrc.json +1 -2
- package/lib/render/DuplicateChecker.js +1 -1
- package/lib/render/manageConstraints.js +36 -33
- package/lib/render/toCdl.js +174 -275
- package/lib/render/toHdbcds.js +203 -122
- package/lib/render/toRename.js +7 -10
- package/lib/render/toSql.js +161 -82
- package/lib/render/utils/common.js +22 -8
- package/lib/render/utils/sql.js +10 -7
- 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/braceExpression.js +4 -2
- package/lib/transform/db/.eslintrc.json +2 -0
- package/lib/transform/db/applyTransformations.js +212 -0
- package/lib/transform/db/assertUnique.js +1 -1
- package/lib/transform/db/associations.js +187 -0
- package/lib/transform/db/cdsPersistence.js +150 -0
- package/lib/transform/db/constraints.js +61 -56
- package/lib/transform/db/expansion.js +50 -29
- package/lib/transform/db/flattening.js +556 -106
- package/lib/transform/db/groupByOrderBy.js +3 -1
- package/lib/transform/db/temporal.js +236 -0
- package/lib/transform/db/transformExists.js +103 -28
- package/lib/transform/db/views.js +92 -44
- package/lib/transform/draft/.eslintrc.json +38 -0
- package/lib/transform/{db/draft.js → draft/db.js} +9 -7
- package/lib/transform/draft/odata.js +227 -0
- package/lib/transform/forHanaNew.js +98 -783
- package/lib/transform/forOdataNew.js +22 -175
- package/lib/transform/localized.js +36 -32
- package/lib/transform/odata/generateForeignKeyElements.js +3 -3
- package/lib/transform/odata/referenceFlattener.js +95 -89
- package/lib/transform/odata/structureFlattener.js +1 -1
- package/lib/transform/odata/toFinalBaseType.js +86 -12
- package/lib/transform/odata/typesExposure.js +5 -5
- package/lib/transform/odata/utils.js +2 -2
- package/lib/transform/transformUtilsNew.js +47 -33
- package/lib/transform/translateAssocsToJoins.js +13 -30
- package/lib/transform/universalCsn/.eslintrc.json +36 -0
- package/lib/transform/universalCsn/coreComputed.js +170 -0
- package/lib/transform/universalCsn/universalCsnEnricher.js +715 -0
- package/lib/transform/universalCsn/utils.js +63 -0
- package/lib/utils/file.js +8 -3
- package/lib/utils/objectUtils.js +30 -0
- package/lib/utils/timetrace.js +8 -2
- package/package.json +1 -1
- package/share/messages/README.md +26 -0
- package/lib/compiler/definer.js +0 -2349
- package/lib/compiler/resolver.js +0 -2922
- package/lib/transform/db/helpers.js +0 -58
- package/lib/transform/universalCsnEnricher.js +0 -67
|
@@ -42,11 +42,17 @@ const centralMessages = {
|
|
|
42
42
|
'anno-definition': { severity: 'Warning' },
|
|
43
43
|
'anno-duplicate': { severity: 'Error', configurableFor: true }, // does not hurt us
|
|
44
44
|
'anno-duplicate-unrelated-layer': { severity: 'Error', configurableFor: true }, // does not hurt us
|
|
45
|
+
'anno-invalid-sql-element': { severity: 'Error', configurableFor: true }, // @sql.prepend/append - configurable for "I know what I'm doing"
|
|
46
|
+
'anno-invalid-sql-struct': { severity: 'Error', configurableFor: true }, // @sql.prepend/append - configurable for "I know what I'm doing"
|
|
47
|
+
'anno-invalid-sql-kind': { severity: 'Error', configurableFor: true }, // @sql.prepend/append - configurable for "I know what I'm doing"
|
|
48
|
+
'anno-invalid-sql-view': { severity: 'Error', configurableFor: true }, // @sql.prepend/append - configurable for "I know what I'm doing"
|
|
49
|
+
'anno-invalid-sql-view-element': { severity: 'Error', configurableFor: true }, // @sql.prepend/append - configurable for "I know what I'm doing"
|
|
45
50
|
'anno-undefined-action': { severity: 'Info' },
|
|
46
51
|
'anno-undefined-art': { severity: 'Info' }, // for annotate statement (for CDL path root)
|
|
47
52
|
'anno-undefined-def': { severity: 'Info' }, // for annotate statement (for CSN or CDL path cont)
|
|
48
53
|
'anno-undefined-element': { severity: 'Info' },
|
|
49
54
|
'anno-undefined-param': { severity: 'Info' },
|
|
55
|
+
'anno-unexpected-ellipsis-layers': { severity: 'Error', configurableFor: true }, // TODO(v3): Merge with anno-unexpected-ellipsis and make non-configurable
|
|
50
56
|
|
|
51
57
|
'args-expected-named': { severity: 'Error', configurableFor: 'deprecated' }, // future --sloppy
|
|
52
58
|
'args-no-params': { severity: 'Error', configurableFor: 'deprecated' }, // future --sloppy
|
|
@@ -54,13 +60,14 @@ const centralMessages = {
|
|
|
54
60
|
|
|
55
61
|
'assoc-in-array': { severity: 'Error', configurableFor: 'deprecated' }, // not supported yet
|
|
56
62
|
'assoc-as-type': { severity: 'Error', configurableFor: 'deprecated' }, // TODO: allow more, but not all
|
|
63
|
+
'def-unexpected-paramview-assoc': { severity: 'Error' },
|
|
64
|
+
'def-unexpected-calcview-assoc': { severity: 'Error' },
|
|
57
65
|
|
|
58
66
|
'check-proper-type': { severity: 'Error', configurableFor: [ 'compile' ] },
|
|
59
67
|
'check-proper-type-of': { severity: 'Info', errorFor: [ 'for.odata', 'to.edmx', 'to.hdbcds', 'to.sql', 'to.rename' ] },
|
|
60
68
|
|
|
61
69
|
'expr-no-filter': { severity: 'Error', configurableFor: 'deprecated' },
|
|
62
70
|
|
|
63
|
-
'empty-entity': { severity: 'Info', errorFor: [ 'to.hdbcds', 'to.sql', 'to.rename' ] },
|
|
64
71
|
'empty-type': { severity: 'Info' }, // only still an error in old transformers
|
|
65
72
|
|
|
66
73
|
// Structured types were warned about but made CSN un-recompilable.
|
|
@@ -69,7 +76,7 @@ const centralMessages = {
|
|
|
69
76
|
// TODO: rename to ref-expected-XYZ
|
|
70
77
|
'expected-type': { severity: 'Error' },
|
|
71
78
|
'ref-sloppy-type': { severity: 'Error' },
|
|
72
|
-
'
|
|
79
|
+
'type-unexpected-typeof': { severity: 'Error', configurableFor: 'deprecated' }, // TODO: make it non-config
|
|
73
80
|
'expected-actionparam-type': { severity: 'Error' },
|
|
74
81
|
'ref-sloppy-actionparam-type': { severity: 'Error' },
|
|
75
82
|
'expected-event-type': { severity: 'Error' },
|
|
@@ -89,6 +96,7 @@ const centralMessages = {
|
|
|
89
96
|
'query-undefined-element': { severity: 'Error' },
|
|
90
97
|
'query-unexpected-assoc-hdbcds': { severity: 'Error' },
|
|
91
98
|
'query-unexpected-structure-hdbcds': { severity: 'Error' },
|
|
99
|
+
'query-ignoring-param-nullability': { severity: 'Info' },
|
|
92
100
|
|
|
93
101
|
'recalculated-localized': { severity: 'Info' }, // KEEP: Downgrade in lib/transform/translateAssocsToJoins.js
|
|
94
102
|
'redirected-implicitly-ambiguous': { severity: 'Error', configurableFor: true }, // does not hurt us - TODO: ref-ambiguous-target
|
|
@@ -99,6 +107,7 @@ const centralMessages = {
|
|
|
99
107
|
'ref-undefined-def': { severity: 'Error' },
|
|
100
108
|
'ref-undefined-var': { severity: 'Error' },
|
|
101
109
|
'ref-undefined-element': { severity: 'Error' },
|
|
110
|
+
'ref-unknown-var': { severity: 'Info' },
|
|
102
111
|
'ref-obsolete-parameters': { severity: 'Error', configurableFor: true }, // does not hurt us
|
|
103
112
|
'ref-undefined-param': { severity: 'Error' },
|
|
104
113
|
'ref-rejected-on': { severity: 'Error' },
|
|
@@ -126,8 +135,17 @@ const centralMessages = {
|
|
|
126
135
|
'syntax-fragile-alias': { severity: 'Error', configurableFor: true },
|
|
127
136
|
'syntax-fragile-ident': { severity: 'Error', configurableFor: true },
|
|
128
137
|
|
|
138
|
+
'syntax-invalid-extend': { severity: 'Error' },
|
|
139
|
+
|
|
140
|
+
'syntax-invalid-text-block' : { severity: 'Error' },
|
|
141
|
+
'syntax-unknown-escape': { severity: 'Error', configurableFor: true },
|
|
142
|
+
'syntax-invalid-escape': { severity: 'Error' },
|
|
143
|
+
'syntax-missing-escape': { severity: 'Error' },
|
|
144
|
+
|
|
129
145
|
'type-managed-composition': { severity: 'Error', configurableFor: 'deprecated' }, // TODO: non-config
|
|
130
146
|
|
|
147
|
+
'def-missing-element': { severity: 'Error' },
|
|
148
|
+
|
|
131
149
|
'unexpected-keys-for-composition': { severity: 'Error' }, // TODO: more than 30 chars
|
|
132
150
|
'unmanaged-as-key': { severity: 'Error', configurableFor: 'deprecated' }, // is confusing
|
|
133
151
|
'composition-as-key': { severity: 'Error', configurableFor: 'deprecated' }, // is confusing and not supported
|
|
@@ -144,8 +162,10 @@ const centralMessages = {
|
|
|
144
162
|
|
|
145
163
|
// For messageIds, where no text has been provided via code (central def)
|
|
146
164
|
const centralMessageTexts = {
|
|
165
|
+
'anno-duplicate': 'Duplicate assignment with $(ANNO)',
|
|
147
166
|
'anno-mismatched-ellipsis': 'An array with $(CODE) can only be used if there is an assignment below with an array value',
|
|
148
|
-
'anno-unexpected-ellipsis': '
|
|
167
|
+
'anno-unexpected-ellipsis': 'No base annotation available to apply $(CODE)',
|
|
168
|
+
'anno-unexpected-ellipsis-layers': 'No base annotation available to apply $(CODE)',
|
|
149
169
|
'missing-type-parameter': 'Missing value for type parameter $(NAME) in reference to type $(ID)',
|
|
150
170
|
'syntax-csn-expected-object': 'Expected object for property $(PROP)',
|
|
151
171
|
'syntax-csn-expected-column': 'Expected object or string \'*\' for property $(PROP)',
|
|
@@ -167,6 +187,23 @@ const centralMessageTexts = {
|
|
|
167
187
|
one: 'Expected array in $(PROP) to have at least one item',
|
|
168
188
|
suffix: 'With sibling property $(OTHERPROP), expected array in $(PROP) to have at least one item',
|
|
169
189
|
},
|
|
190
|
+
'syntax-invalid-extend': 'Can\'t extend an element with $(KIND)',
|
|
191
|
+
'syntax-invalid-text-block': 'Missing newline in text block',
|
|
192
|
+
'syntax-unknown-escape': 'Unknown escape sequence $(CODE)',
|
|
193
|
+
'syntax-invalid-escape': {
|
|
194
|
+
std: 'Invalid escape sequence $(CODE)',
|
|
195
|
+
octal: 'Octal escape sequences are not supported. Use unicode escapes instead',
|
|
196
|
+
whitespace: 'Unknown escape sequence: Can\'t escape whitespace',
|
|
197
|
+
codepoint: 'Undefined code-point for $(CODE)',
|
|
198
|
+
'unicode-hex': 'Expected hexadecimal numbers for unicode escape but found $(CODE)',
|
|
199
|
+
'hex-count': 'Expected $(NUMBER) hexadecimal numbers for escape sequence but found $(CODE)',
|
|
200
|
+
'unicode-brace': 'Missing closing brace for unicode escape sequence',
|
|
201
|
+
'language-identifier': 'Escape sequences in text-block\'s language identifier are not allowed',
|
|
202
|
+
},
|
|
203
|
+
'syntax-missing-escape': {
|
|
204
|
+
std: 'Missing escape. Replace $(CODE) with $(NEWCODE)',
|
|
205
|
+
placeholder: 'Placeholders are not supported. Replace $(CODE) with $(NEWCODE)',
|
|
206
|
+
},
|
|
170
207
|
'ref-undefined-def': {
|
|
171
208
|
std: 'Artifact $(ART) has not been found',
|
|
172
209
|
// TODO: proposal 'No definition of $(NAME) found',
|
|
@@ -178,17 +215,21 @@ const centralMessageTexts = {
|
|
|
178
215
|
std: 'Element $(ART) has not been found',
|
|
179
216
|
element: 'Artifact $(ART) has no element $(MEMBER)'
|
|
180
217
|
},
|
|
218
|
+
'ref-unknown-var': {
|
|
219
|
+
std: 'Replacement $(ID) not found'
|
|
220
|
+
},
|
|
221
|
+
'ref-unexpected-draft-enabled': 'Composition in draft-enabled entity can\'t lead to another entity with $(ANNO)',
|
|
181
222
|
'ref-rejected-on': {
|
|
182
223
|
std: 'Do not refer to a artefact like $(ID) in the explicit ON of a redirection', // Not used
|
|
183
224
|
mixin: 'Do not refer to a mixin like $(ID) in the explicit ON of a redirection',
|
|
184
225
|
alias: 'Do not refer to a source element (via table alias $(ID)) in the explicit ON of a redirection',
|
|
185
226
|
},
|
|
186
|
-
'
|
|
187
|
-
std: '
|
|
188
|
-
type: '
|
|
189
|
-
event: '
|
|
190
|
-
param: '
|
|
191
|
-
select: '
|
|
227
|
+
'type-unexpected-typeof': {
|
|
228
|
+
std: 'Unexpected $(KEYWORD) for the type reference here',
|
|
229
|
+
type: 'Unexpected $(KEYWORD) in type of a type definition',
|
|
230
|
+
event: 'Unexpected $(KEYWORD) for the type of an event',
|
|
231
|
+
param: 'Unexpected $(KEYWORD) for the type of a parameter definition',
|
|
232
|
+
select: 'Unexpected $(KEYWORD) for type references in queries',
|
|
192
233
|
},
|
|
193
234
|
'anno-builtin': 'Builtin types should not be annotated. Use custom type instead',
|
|
194
235
|
'anno-undefined-def': 'Artifact $(ART) has not been found',
|
|
@@ -207,6 +248,22 @@ const centralMessageTexts = {
|
|
|
207
248
|
param: 'Artifact $(ART) has no parameter $(MEMBER)'
|
|
208
249
|
},
|
|
209
250
|
|
|
251
|
+
'def-unexpected-paramview-assoc': {
|
|
252
|
+
std: 'SAP HANA does no support associations in/to parameterized entities',
|
|
253
|
+
view: 'SAP HANA does no support associations in parameterized entities',
|
|
254
|
+
target: 'SAP HANA does no support associations to parameterized entities',
|
|
255
|
+
},
|
|
256
|
+
'def-unexpected-calcview-assoc': {
|
|
257
|
+
std: 'SAP HANA does not allow associations in/to entities annotated with $(ANNO)',
|
|
258
|
+
'entity-persistence': 'SAP HANA does not allow associations in entities annotated with $(ANNO)',
|
|
259
|
+
'target-persistence': 'SAP HANA does not allow associations pointing to entities annotated with $(ANNO)',
|
|
260
|
+
},
|
|
261
|
+
|
|
262
|
+
'def-missing-element': {
|
|
263
|
+
std: 'Expecting entity to have at least one non-virtual element',
|
|
264
|
+
view: 'Expecting view to have at least one non-virtual element'
|
|
265
|
+
},
|
|
266
|
+
|
|
210
267
|
'duplicate-definition': {
|
|
211
268
|
std: 'Duplicate definition of $(NAME)',
|
|
212
269
|
absolute: 'Duplicate definition of artifact $(NAME)',
|
|
@@ -235,6 +292,10 @@ const centralMessageTexts = {
|
|
|
235
292
|
|
|
236
293
|
'query-unexpected-assoc-hdbcds': 'Publishing a managed association in a view is not possible for “hdbcds” naming mode',
|
|
237
294
|
'query-unexpected-structure-hdbcds': 'Publishing a structured element in a view is not possible for “hdbcds” naming mode',
|
|
295
|
+
'query-ignoring-param-nullability': {
|
|
296
|
+
std: 'Ignoring nullability constraint on parameter when generating SAP HANA CDS view',
|
|
297
|
+
sql: 'Ignoring nullability constraint on parameter when generating SQL view'
|
|
298
|
+
},
|
|
238
299
|
|
|
239
300
|
'ref-sloppy-type': 'A type or an element is expected here',
|
|
240
301
|
'ref-sloppy-actionparam-type': 'A type, an element, or a service entity is expected here',
|
|
@@ -273,6 +334,11 @@ const centralMessageTexts = {
|
|
|
273
334
|
'odata-spec-violation-type': 'Expected element to have a type',
|
|
274
335
|
'odata-spec-violation-property-name': 'Expected element name to be different from declaring $(KIND)',
|
|
275
336
|
'odata-spec-violation-namespace': 'Expected service name not to be one of the reserved names $(NAMES)',
|
|
337
|
+
// Other odata/edm errors
|
|
338
|
+
'odata-definition-exists': {
|
|
339
|
+
std: 'Entity can\'t be created due to name collision with existing definition $(NAME)',
|
|
340
|
+
proxy: 'No proxy entity created due to name collision with existing definition $(NAME) of kind $(KIND)'
|
|
341
|
+
}
|
|
276
342
|
}
|
|
277
343
|
|
|
278
344
|
/**
|
package/lib/base/messages.js
CHANGED
|
@@ -125,6 +125,7 @@ class CompileMessage {
|
|
|
125
125
|
* @param {CSN.MessageSeverity} [severity='Error'] Severity: Debug, Info, Warning, Error
|
|
126
126
|
* @param {string} [id] The ID of the message - visible as property messageId
|
|
127
127
|
* @param {any} [home]
|
|
128
|
+
* @param {string} [moduleName] Name of the module that created this message
|
|
128
129
|
*
|
|
129
130
|
* @memberOf CompileMessage
|
|
130
131
|
*/
|
|
@@ -175,22 +176,6 @@ function dollarLocation( location ) {
|
|
|
175
176
|
return loc;
|
|
176
177
|
}
|
|
177
178
|
|
|
178
|
-
/**
|
|
179
|
-
* Handle compiler messages, i.e. throw a compiler exception if there are errors.
|
|
180
|
-
*
|
|
181
|
-
* @param {object} model CSN or XSN
|
|
182
|
-
* @param {CSN.Options} [options]
|
|
183
|
-
* @deprecated Use throwWithError() from makeMessageFunction instead.
|
|
184
|
-
*/
|
|
185
|
-
function handleMessages( model, options = {} ) {
|
|
186
|
-
const messages = options.messages;
|
|
187
|
-
if (messages && messages.length) {
|
|
188
|
-
if (hasErrors( messages ))
|
|
189
|
-
throw new CompilationError( messages, options.attachValidNames && model );
|
|
190
|
-
}
|
|
191
|
-
return model;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
179
|
const severitySpecs = {
|
|
195
180
|
error: { name: 'Error', level: 0 },
|
|
196
181
|
warning: { name: 'Warning', level: 1 },
|
|
@@ -282,16 +267,16 @@ function compareSeverities( a, b ) {
|
|
|
282
267
|
/**
|
|
283
268
|
* @todo This was copied from somewhere just to make CSN paths work.
|
|
284
269
|
* @param {CSN.Model} model
|
|
285
|
-
* @param {CSN.Path}
|
|
270
|
+
* @param {CSN.Path} csnPath
|
|
286
271
|
*/
|
|
287
|
-
function searchForLocation( model,
|
|
272
|
+
function searchForLocation( model, csnPath ) {
|
|
288
273
|
if (!model)
|
|
289
274
|
return null;
|
|
290
275
|
// Don't display a location if we cannot find one!
|
|
291
276
|
let lastLocation = null;
|
|
292
277
|
/** @type {object} */
|
|
293
278
|
let currentStep = model;
|
|
294
|
-
for (const step of
|
|
279
|
+
for (const step of csnPath) {
|
|
295
280
|
if (!currentStep)
|
|
296
281
|
return lastLocation;
|
|
297
282
|
currentStep = currentStep[step];
|
|
@@ -672,13 +657,16 @@ function ignoreTextTransform() {
|
|
|
672
657
|
|
|
673
658
|
function transformManyWith( t, sorted ) {
|
|
674
659
|
return function transformMany( many, r, args, texts ) {
|
|
675
|
-
const prop = ['none','one'][ many.length ];
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
660
|
+
const prop = ['none','one','two'][ many.length ];
|
|
661
|
+
const names = many.map(t);
|
|
662
|
+
if (sorted)
|
|
663
|
+
names.sort();
|
|
664
|
+
if (!prop || !texts[prop] || args['#'] )
|
|
665
|
+
return names.join(', ');
|
|
680
666
|
r['#'] = prop; // text variant
|
|
681
|
-
|
|
667
|
+
if (many.length === 2)
|
|
668
|
+
r.second = names[1];
|
|
669
|
+
return many.length && names[0];
|
|
682
670
|
};
|
|
683
671
|
}
|
|
684
672
|
|
|
@@ -793,7 +781,7 @@ function replaceInString( text, params ) {
|
|
|
793
781
|
start = pattern.lastIndex;
|
|
794
782
|
}
|
|
795
783
|
parts.push( text.substring( start ) );
|
|
796
|
-
let remain = ('#'
|
|
784
|
+
let remain = (params['#']) ? [] : Object.keys( params ).filter( n => params[n] );
|
|
797
785
|
return (remain.length)
|
|
798
786
|
? parts.join('') + '; ' +
|
|
799
787
|
remain.map( n => n.toUpperCase() + ' = ' + params[n] ).join(', ')
|
|
@@ -845,7 +833,10 @@ function messageHash(msg) {
|
|
|
845
833
|
if(!msg.home)
|
|
846
834
|
return messageString(msg);
|
|
847
835
|
const copy = {...msg};
|
|
848
|
-
|
|
836
|
+
// Note: This is a hack. deduplicateMessages() would otherwise remove
|
|
837
|
+
// all but one message about duplicated artifacts.
|
|
838
|
+
if (!msg.messageId || !msg.messageId.includes('duplicate'))
|
|
839
|
+
copy.$location = undefined;
|
|
849
840
|
return messageString(copy);
|
|
850
841
|
}
|
|
851
842
|
|
|
@@ -1082,7 +1073,7 @@ function deduplicateMessages( messages ) {
|
|
|
1082
1073
|
|
|
1083
1074
|
function shortArtName( art ) {
|
|
1084
1075
|
const { name } = art;
|
|
1085
|
-
if ([ 'select', 'action', 'alias', 'param' ].every( n => name[n] == null ) &&
|
|
1076
|
+
if ([ 'select', 'action', 'alias', 'param' ].every( n => name[n] == null || name[n] === 1 ) &&
|
|
1086
1077
|
!name.absolute.includes(':'))
|
|
1087
1078
|
return quote.name( name.element ? `${ name.absolute }:${ name.element }` : name.absolute );
|
|
1088
1079
|
return artName( art );
|
|
@@ -1095,13 +1086,15 @@ function artName( art, omit ) {
|
|
|
1095
1086
|
r.push( (art.kind === 'extend' ? 'block:' : 'query:') + name.select ); // TODO: rename to 'select:1' and consider whether there are more selects
|
|
1096
1087
|
if (name.action && omit !== 'action')
|
|
1097
1088
|
r.push( memberActionName(art) + ':' + quoted( name.action ) );
|
|
1098
|
-
if (name.alias)
|
|
1089
|
+
if (name.alias && art.kind !== '$self')
|
|
1099
1090
|
r.push( (art.kind === 'mixin' ? 'mixin:' : 'alias:') + quoted( name.alias ) )
|
|
1100
1091
|
if (name.param != null && omit !== 'param')
|
|
1101
1092
|
r.push( name.param ? 'param:' + quoted( name.param ) : 'returns' ); // TODO: join
|
|
1102
1093
|
if (name.element && omit !== 'element')
|
|
1103
1094
|
// r.push( `${ art.kind }: ${ quoted( name.element )}` ); or even better element:"assoc"/key:"i" same with enum
|
|
1104
1095
|
r.push( (art.kind === 'enum' ? 'enum:' : 'element:') + quoted( name.element ) );
|
|
1096
|
+
if (art.kind === '$self')
|
|
1097
|
+
r.push( 'alias:' + quoted( name.alias ) ) // should be late due to $self in anonymous aspect
|
|
1105
1098
|
return r.join('/');
|
|
1106
1099
|
}
|
|
1107
1100
|
|
|
@@ -1114,6 +1107,7 @@ function memberActionName( art ) {
|
|
|
1114
1107
|
return 'action';
|
|
1115
1108
|
}
|
|
1116
1109
|
|
|
1110
|
+
// TODO: XSN-specific things should probably move out
|
|
1117
1111
|
function homeName( art, absoluteOnly ) {
|
|
1118
1112
|
if (!art)
|
|
1119
1113
|
return art;
|
|
@@ -1129,8 +1123,10 @@ function homeName( art, absoluteOnly ) {
|
|
|
1129
1123
|
return homeName( art.name._artifact, absoluteOnly ); // use corresponding definition
|
|
1130
1124
|
else if (absoluteOnly)
|
|
1131
1125
|
return art.name.absolute;
|
|
1132
|
-
|
|
1133
|
-
|
|
1126
|
+
let main = art._main || art;
|
|
1127
|
+
while (main._outer) // anonymous aspect
|
|
1128
|
+
main = main._outer._main;
|
|
1129
|
+
return main.kind + ':' + artName( art );
|
|
1134
1130
|
}
|
|
1135
1131
|
|
|
1136
1132
|
// The "home" for extensions is handled differently because `_artifact` is not
|
|
@@ -1184,9 +1180,9 @@ function constructSemanticLocationFromCsnPath(csnPath, model) {
|
|
|
1184
1180
|
|
|
1185
1181
|
// remove definitions
|
|
1186
1182
|
csnPath.shift();
|
|
1187
|
-
const
|
|
1188
|
-
let currentThing = model.definitions[
|
|
1189
|
-
let result = `${ (currentThing && currentThing.kind) ? currentThing.kind : 'artifact' }:${ _quoted(
|
|
1183
|
+
const artifactName = csnPath.shift();
|
|
1184
|
+
let currentThing = model.definitions[artifactName];
|
|
1185
|
+
let result = `${ (currentThing && currentThing.kind) ? currentThing.kind : 'artifact' }:${ _quoted(artifactName) }`;
|
|
1190
1186
|
|
|
1191
1187
|
if (!currentThing)
|
|
1192
1188
|
return result;
|
|
@@ -1438,12 +1434,12 @@ module.exports = {
|
|
|
1438
1434
|
createMessageFunctions,
|
|
1439
1435
|
makeMessageFunction,
|
|
1440
1436
|
artName,
|
|
1441
|
-
handleMessages,
|
|
1442
1437
|
sortMessages: (m => m.sort(compareMessage)),
|
|
1443
1438
|
sortMessagesSeverityAware: (m => m.sort(compareMessageSeverityAware)),
|
|
1444
1439
|
deduplicateMessages,
|
|
1445
1440
|
CompileMessage,
|
|
1446
1441
|
CompilationError,
|
|
1442
|
+
isMessageDowngradable: isDowngradable,
|
|
1447
1443
|
explainMessage,
|
|
1448
1444
|
hasMessageExplanation,
|
|
1449
1445
|
messageIdsWithExplanation,
|
package/lib/base/model.js
CHANGED
|
@@ -63,7 +63,7 @@ function isBetaEnabled( options, feature ) {
|
|
|
63
63
|
*/
|
|
64
64
|
function isDeprecatedEnabled( options, feature = null ) {
|
|
65
65
|
const { deprecated } = options;
|
|
66
|
-
if(!feature)
|
|
66
|
+
if (!feature)
|
|
67
67
|
return !!deprecated;
|
|
68
68
|
return deprecated && typeof deprecated === 'object' && deprecated[feature];
|
|
69
69
|
}
|
|
@@ -93,63 +93,6 @@ function forEachMember( construct, callback, target ) {
|
|
|
93
93
|
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
// Apply function `callback(member, memberName, prop)` to each member in
|
|
97
|
-
// `construct`, recursively (i.e. also for sub-elements of elements).
|
|
98
|
-
function forEachMemberRecursively( construct, callback ) {
|
|
99
|
-
forEachMember( construct, ( member, memberName, prop ) => {
|
|
100
|
-
callback( member, memberName, prop );
|
|
101
|
-
// Descend into nested members, too
|
|
102
|
-
forEachMemberRecursively( member, callback );
|
|
103
|
-
});
|
|
104
|
-
// If 'construct' has more than one query, descend into the elements of the remaining ones, too
|
|
105
|
-
if (construct.$queries && construct.$queries.length > 1) {
|
|
106
|
-
construct.$queries.slice(1).forEach(query => forEachMemberRecursively(query, callback));
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Apply function `callback` to all members of object `obj` (main artifact or
|
|
112
|
-
* parent member). Members are considered those in dictionaries `elements`,
|
|
113
|
-
* `enum`, `actions` and `params` of `obj`, `elements` and `enums` are also
|
|
114
|
-
* searched inside property `items` (array of). `$queries`, `mixin` and
|
|
115
|
-
* `columns` are also visited in contrast to `forEachMember()`.
|
|
116
|
-
* See function `forEachGeneric()` for details.
|
|
117
|
-
*
|
|
118
|
-
* @param {XSN.Artifact} construct
|
|
119
|
-
* @param {(member: object, memberName: string, prop: string) => any} callback
|
|
120
|
-
* @param {object} [target]
|
|
121
|
-
*/
|
|
122
|
-
function forEachMemberWithQuery( construct, callback, target ) {
|
|
123
|
-
let obj = construct.returns || construct; // why the extra `returns` for actions?
|
|
124
|
-
obj = obj.items || obj;
|
|
125
|
-
forEachGeneric( target || obj, 'elements', callback );
|
|
126
|
-
forEachGeneric( obj, 'enum', callback );
|
|
127
|
-
forEachGeneric( obj, 'foreignKeys', callback );
|
|
128
|
-
forEachGeneric( construct, 'actions', callback );
|
|
129
|
-
forEachGeneric( construct, 'params', callback );
|
|
130
|
-
// For Queries
|
|
131
|
-
forEachGeneric( construct, '$queries', callback );
|
|
132
|
-
forEachGeneric( construct, 'mixin', callback );
|
|
133
|
-
forEachGeneric( construct, 'columns', callback );
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Apply function `callback(member, memberName, prop)` to each member in
|
|
138
|
-
* `construct`, recursively (i.e. also for sub-elements of elements).
|
|
139
|
-
* In contrast to `forEachMemberRecursively()` this function also traverses
|
|
140
|
-
* queries and mixins.
|
|
141
|
-
*
|
|
142
|
-
* @param {XSN.Artifact} construct
|
|
143
|
-
* @param {(member: object, memberName: string, prop: string) => any} callback
|
|
144
|
-
*/
|
|
145
|
-
function forEachMemberRecursivelyWithQuery( construct, callback ) {
|
|
146
|
-
forEachMemberWithQuery( construct, ( member, memberName, prop ) => {
|
|
147
|
-
callback( member, memberName, prop );
|
|
148
|
-
// Descend into nested members, too
|
|
149
|
-
forEachMemberRecursivelyWithQuery( member, callback );
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
|
|
153
96
|
// Apply function `callback` to all objects in dictionary `dict`, including all
|
|
154
97
|
// duplicates (found under the same name). Function `callback` is called with
|
|
155
98
|
// the following arguments: the object, the name, and -if it is a duplicate-
|
|
@@ -157,7 +100,7 @@ function forEachMemberRecursivelyWithQuery( construct, callback ) {
|
|
|
157
100
|
function forEachGeneric( obj, prop, callback ) {
|
|
158
101
|
let dict = obj[prop];
|
|
159
102
|
for (let name in dict) {
|
|
160
|
-
|
|
103
|
+
obj = dict[name];
|
|
161
104
|
callback( obj, name, prop );
|
|
162
105
|
if (Array.isArray(obj.$duplicates)) // redefinitions
|
|
163
106
|
obj.$duplicates.forEach( o => callback( o, name, prop ) )
|
|
@@ -189,9 +132,6 @@ module.exports = {
|
|
|
189
132
|
queryOps,
|
|
190
133
|
forEachDefinition,
|
|
191
134
|
forEachMember,
|
|
192
|
-
forEachMemberRecursively,
|
|
193
|
-
forEachMemberWithQuery,
|
|
194
|
-
forEachMemberRecursivelyWithQuery,
|
|
195
135
|
forEachGeneric,
|
|
196
136
|
forEachInOrder,
|
|
197
137
|
setProp,
|