@sap/cds-compiler 2.13.8 → 2.15.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/CHANGELOG.md +109 -4
  2. package/bin/cdsc.js +112 -37
  3. package/lib/api/main.js +20 -22
  4. package/lib/api/options.js +2 -3
  5. package/lib/api/validate.js +6 -6
  6. package/lib/base/message-registry.js +89 -14
  7. package/lib/base/messages.js +85 -64
  8. package/lib/base/optionProcessorHelper.js +19 -0
  9. package/lib/checks/annotationsOData.js +11 -32
  10. package/lib/checks/arrayOfs.js +1 -34
  11. package/lib/checks/validator.js +2 -4
  12. package/lib/compiler/assert-consistency.js +1 -0
  13. package/lib/compiler/base.js +1 -0
  14. package/lib/compiler/builtins.js +11 -0
  15. package/lib/compiler/checks.js +22 -70
  16. package/lib/compiler/define.js +59 -11
  17. package/lib/compiler/extend.js +20 -3
  18. package/lib/compiler/finalize-parse-cdl.js +26 -20
  19. package/lib/compiler/index.js +75 -26
  20. package/lib/compiler/populate.js +6 -5
  21. package/lib/compiler/propagator.js +4 -1
  22. package/lib/compiler/resolve.js +104 -16
  23. package/lib/compiler/shared.js +61 -27
  24. package/lib/compiler/tweak-assocs.js +7 -1
  25. package/lib/edm/annotations/genericTranslation.js +33 -15
  26. package/lib/edm/csn2edm.js +216 -98
  27. package/lib/edm/edm.js +298 -225
  28. package/lib/edm/edmPreprocessor.js +486 -415
  29. package/lib/edm/edmUtils.js +22 -22
  30. package/lib/gen/Dictionary.json +90 -16
  31. package/lib/gen/language.checksum +1 -1
  32. package/lib/gen/language.interp +3 -1
  33. package/lib/gen/languageParser.js +4636 -4368
  34. package/lib/json/csnVersion.js +10 -11
  35. package/lib/json/from-csn.js +3 -2
  36. package/lib/json/to-csn.js +0 -2
  37. package/lib/language/docCommentParser.js +2 -2
  38. package/lib/language/genericAntlrParser.js +47 -2
  39. package/lib/language/language.g4 +59 -27
  40. package/lib/main.d.ts +19 -1
  41. package/lib/main.js +6 -0
  42. package/lib/model/csnRefs.js +33 -6
  43. package/lib/model/csnUtils.js +193 -75
  44. package/lib/model/enrichCsn.js +1 -0
  45. package/lib/model/revealInternalProperties.js +2 -2
  46. package/lib/modelCompare/compare.js +6 -6
  47. package/lib/optionProcessor.js +62 -26
  48. package/lib/render/toCdl.js +844 -679
  49. package/lib/render/toHdbcds.js +189 -243
  50. package/lib/render/toSql.js +180 -198
  51. package/lib/render/utils/common.js +131 -15
  52. package/lib/transform/db/.eslintrc.json +1 -1
  53. package/lib/transform/db/associations.js +2 -2
  54. package/lib/transform/db/constraints.js +3 -1
  55. package/lib/transform/db/expansion.js +15 -10
  56. package/lib/transform/db/flattening.js +94 -64
  57. package/lib/transform/db/transformExists.js +7 -7
  58. package/lib/transform/db/views.js +6 -3
  59. package/lib/transform/forHanaNew.js +43 -26
  60. package/lib/transform/forOdataNew.js +43 -42
  61. package/lib/transform/localized.js +12 -7
  62. package/lib/transform/odata/toFinalBaseType.js +5 -5
  63. package/lib/transform/odata/typesExposure.js +145 -197
  64. package/lib/transform/transformUtilsNew.js +9 -12
  65. package/lib/transform/translateAssocsToJoins.js +1 -1
  66. package/lib/transform/universalCsn/coreComputed.js +5 -3
  67. package/lib/transform/universalCsn/universalCsnEnricher.js +27 -5
  68. package/lib/utils/moduleResolve.js +13 -6
  69. package/package.json +1 -1
  70. package/share/messages/message-explanations.json +2 -1
  71. package/share/messages/syntax-expected-integer.md +37 -0
  72. package/lib/transform/odata/attachPath.js +0 -96
  73. package/lib/transform/odata/expandStructKeysInAssociations.js +0 -59
  74. package/lib/transform/odata/generateForeignKeyElements.js +0 -261
  75. package/lib/transform/odata/referenceFlattener.js +0 -296
  76. package/lib/transform/odata/sortByAssociationDependency.js +0 -105
  77. package/lib/transform/odata/structuralPath.js +0 -72
  78. package/lib/transform/odata/structureFlattener.js +0 -171
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const { setProp, isBetaEnabled } = require('../base/model');
4
- const { getUtils, cloneCsn,
4
+ const { getUtils, cloneCsnNonDict,
5
5
  forEachMemberRecursively, forAllQueries, applyTransformationsOnNonDictionary,
6
6
  getArtifactDatabaseNameOf, getElementDatabaseNameOf, isBuiltinType, applyTransformations,
7
7
  isAspect, walkCsnPath,
@@ -16,7 +16,7 @@ const { rejectManagedAssociationsAndStructuresForHdbcdsNames } = require('../che
16
16
  const { addLocalizationViewsWithJoins, addLocalizationViews } = require('../transform/localized');
17
17
  const { timetrace } = require('../utils/timetrace');
18
18
  const { createReferentialConstraints, assertConstraintIdentifierUniqueness } = require('./db/constraints');
19
- const { createDict } = require('../utils/objectUtils');
19
+ const { createDict, forEach } = require('../utils/objectUtils');
20
20
  const handleExists = require('./db/transformExists');
21
21
  const replaceAssociationsInGroupByOrderBy = require('./db/groupByOrderBy');
22
22
  const _forEachDefinition = require('../model/csnUtils').forEachDefinition;
@@ -106,7 +106,7 @@ function transformForHanaWithCsn(inputModel, options, moduleName) {
106
106
  // copy the model as we don't want to change the input model
107
107
  timetrace.start('HANA transformation');
108
108
  /** @type {CSN.Model} */
109
- let csn = cloneCsn(inputModel, options);
109
+ let csn = cloneCsnNonDict(inputModel, options);
110
110
 
111
111
 
112
112
 
@@ -116,14 +116,14 @@ function transformForHanaWithCsn(inputModel, options, moduleName) {
116
116
 
117
117
  let message, error, warning, info; // message functions
118
118
  /** @type {() => void} */
119
- let throwWithError;
119
+ let throwWithAnyError;
120
120
  let artifactRef, inspectRef, effectiveType, get$combined,
121
121
  getFinalBaseType, // csnUtils (csnRefs)
122
122
  addDefaultTypeFacets, expandStructsInExpression; // transformUtils
123
123
 
124
124
  bindCsnReference();
125
125
 
126
- throwWithError(); // reclassify and throw in case of non-configurable errors
126
+ throwWithAnyError(); // reclassify and throw in case of non-configurable errors
127
127
 
128
128
  if (options.csnFlavor === 'universal' && isBetaEnabled(options, 'enableUniversalCsn')) {
129
129
  enrichUniversalCsn(csn, options);
@@ -146,13 +146,13 @@ function transformForHanaWithCsn(inputModel, options, moduleName) {
146
146
  // Check if structured elements and managed associations are compared in an expression
147
147
  // and expand these structured elements. This tuple expansion allows all other
148
148
  // subsequent procession steps (especially a2j) to see plain paths in expressions.
149
- // If errors are detected, throwWithError() will return from further processing
149
+ // If errors are detected, throwWithAnyError() will return from further processing
150
150
 
151
151
  // If this function is ever undefined, we have a bug in our logic.
152
152
  // @ts-ignore
153
153
  expandStructsInExpression(csn, { drillRef: true });
154
154
 
155
- throwWithError();
155
+ throwWithAnyError();
156
156
 
157
157
  // FIXME: This does something very similar to cloneWithTransformations -> refactor?
158
158
  const transformCsn = transformUtils.transformModel;
@@ -167,7 +167,7 @@ function transformForHanaWithCsn(inputModel, options, moduleName) {
167
167
 
168
168
  if(doA2J) {
169
169
  // Expand a structured thing in: keys, columns, order by, group by
170
- expansion.expandStructureReferences(csn, options, pathDelimiter, {error, info, throwWithError});
170
+ expansion.expandStructureReferences(csn, options, pathDelimiter, {error, info, throwWithAnyError});
171
171
  bindCsnReference();
172
172
  }
173
173
 
@@ -353,7 +353,7 @@ function transformForHanaWithCsn(inputModel, options, moduleName) {
353
353
  if(doA2J)
354
354
  flattening.removeLeadingSelf(csn);
355
355
 
356
- throwWithError();
356
+ throwWithAnyError();
357
357
 
358
358
  timetrace.stop();
359
359
 
@@ -381,7 +381,22 @@ function transformForHanaWithCsn(inputModel, options, moduleName) {
381
381
  // Set when we turn UUID into String, checked during generateDraftForHana
382
382
  '$renamed': killProp,
383
383
  // Set when we remove .key from temporal things, used in localized.js
384
- '$key': killProp
384
+ '$key': killProp,
385
+ // We need .elements easily for rendering - otherwise we have to compute it then
386
+ // Does not fit in the "killers" theme - TODO: Find a better place
387
+ SET: (parent, prop, SET) => {
388
+ if(!SET.elements) {
389
+ const stack = [parent];
390
+ while(stack.length > 0) {
391
+ const query = stack.pop();
392
+
393
+ if(query.SET)
394
+ stack.push(query.SET.args[0]);
395
+ else if(query.SELECT)
396
+ setProp(SET, 'elements', query.SELECT.elements);
397
+ }
398
+ }
399
+ }
385
400
  }
386
401
 
387
402
  applyTransformations(csn, killers, [], { skipIgnore: false});
@@ -393,7 +408,7 @@ function transformForHanaWithCsn(inputModel, options, moduleName) {
393
408
  /* ----------------------------------- Functions start here -----------------------------------------------*/
394
409
 
395
410
  function bindCsnReference(){
396
- ({ error, warning, info, message, throwWithError } = makeMessageFunction(csn, options, moduleName));
411
+ ({ error, warning, info, message, throwWithAnyError } = makeMessageFunction(csn, options, moduleName));
397
412
  ({ artifactRef, inspectRef, effectiveType, getFinalBaseType, get$combined } = getUtils(csn));
398
413
  ({ addDefaultTypeFacets, expandStructsInExpression } = transformUtils.getTransformers(csn, options, pathDelimiter));
399
414
  }
@@ -448,7 +463,7 @@ function transformForHanaWithCsn(inputModel, options, moduleName) {
448
463
  // get$combined also includes elements which are part of "excluding {}"
449
464
  // this shouldn't be an issue here, as such references get rejected
450
465
  const elementsOfQuerySources = get$combined(query);
451
- Object.entries(elementsOfQuerySources).forEach(([id, element]) => {
466
+ forEach(elementsOfQuerySources, (id, element) => {
452
467
  // if the ref points to an element which is not explicitly exposed in the column list,
453
468
  // but through the '*' operator -> replace the $projection / $self with the correct source entity
454
469
  if(id === columnToReplace)
@@ -458,7 +473,7 @@ function transformForHanaWithCsn(inputModel, options, moduleName) {
458
473
 
459
474
  // No implicit CAST in on-condition
460
475
  if(replaceWith && replaceWith.cast) {
461
- const clone = cloneCsn(replaceWith, options);
476
+ const clone = cloneCsnNonDict(replaceWith, options);
462
477
  delete clone.cast;
463
478
  return clone;
464
479
  }
@@ -475,10 +490,14 @@ function transformForHanaWithCsn(inputModel, options, moduleName) {
475
490
  if (!artifact._ignore) {
476
491
  // Do things specific for entities and views (pass 2)
477
492
  if ((artifact.kind === 'entity') && artifact.query) {
478
- forAllQueries(artifact.query, (q, p) => {
479
- transformEntityOrViewPass2(q, artifact, artifactName, p)
480
- replaceAssociationsInGroupByOrderBy(q, options, inspectRef, error, p);
481
- }, [ 'definitions', artifactName, 'query' ]);
493
+ const process = (parent, prop, query, path) => {
494
+ transformEntityOrViewPass2(parent, artifact, artifactName, path.concat(prop))
495
+ replaceAssociationsInGroupByOrderBy(parent, options, inspectRef, error, path.concat(prop));
496
+ return query;
497
+ }
498
+ applyTransformationsOnNonDictionary(csn.definitions, artifactName, {
499
+ SELECT: process
500
+ }, {}, [ 'definitions']);
482
501
  }
483
502
  }
484
503
  }
@@ -618,7 +637,7 @@ function transformForHanaWithCsn(inputModel, options, moduleName) {
618
637
 
619
638
  function handleAssocToJoins() {
620
639
  // With flattening errors, it makes little sense to continue.
621
- throwWithError();
640
+ throwWithAnyError();
622
641
  // the augmentor isn't able to deal with technical configurations and since assoc2join can ignore it we
623
642
  // simply make it invisible and copy it over to the result csn
624
643
  forEachDefinition(csn, art => art.technicalConfig && setProp(art, 'technicalConfig', art.technicalConfig));
@@ -998,24 +1017,22 @@ function transformForHanaWithCsn(inputModel, options, moduleName) {
998
1017
  // (which can currently only be 'positiveInteger') and (optional) the value is in a given range
999
1018
  function checkTypeParamValue(node, paramName, range = null, path = null) {
1000
1019
  const paramValue = node[paramName];
1001
- if (paramValue == undefined) {
1020
+ if (paramValue === undefined || paramValue === null) {
1002
1021
  if(options.toSql || artifact.query || !['cds.Binary','cds.hana.BINARY', 'cds.hana.NCHAR','cds.hana.CHAR'].includes(node.type)) {
1003
1022
  return true;
1004
1023
  } else {
1005
- return error('missing-type-parameter', path, { name: paramName, id: node.type, $reviewed: false });
1024
+ return error('type-missing-argument', path, { name: paramName, id: node.type, $reviewed: false });
1006
1025
  }
1007
1026
  }
1008
1027
  if (range) {
1009
1028
  if (isMaxParameterLengthRestricted(node.type) && range.max && paramValue > range.max) {
1010
- error(null, path,
1011
- { prop: paramName, type: node.type, number: range.max, $reviewed: false },
1012
- 'Expecting parameter $(PROP) for type $(TYPE) to not exceed $(NUMBER)');
1029
+ error('type-unexpected-argument', path,
1030
+ { '#': 'max', prop: paramName, type: node.type, number: range.max, $reviewed: false });
1013
1031
  return false;
1014
1032
  }
1015
1033
  if (range.min && paramValue < range.min) {
1016
- error(null, path,
1017
- { prop: paramName, type: node.type, number: range.min, $reviewed: false },
1018
- 'Expecting parameter $(PROP) for type $(TYPE) to be greater than or equal to $(NUMBER)');
1034
+ error('type-unexpected-argument', path,
1035
+ { '#': 'min', prop: paramName, type: node.type, number: range.min, $reviewed: false });
1019
1036
  return false;
1020
1037
  }
1021
1038
  }
@@ -4,7 +4,7 @@ const { makeMessageFunction } = require('../base/messages');
4
4
  const { isDeprecatedEnabled, isBetaEnabled } = require('../base/model');
5
5
  const transformUtils = require('./transformUtilsNew');
6
6
  const { getUtils,
7
- cloneCsn,
7
+ cloneCsnNonDict,
8
8
  forEachDefinition,
9
9
  forEachMemberRecursively,
10
10
  applyTransformationsOnNonDictionary,
@@ -17,14 +17,12 @@ const { getUtils,
17
17
  const { checkCSNVersion } = require('../json/csnVersion');
18
18
  const validate = require('../checks/validator');
19
19
  const { isArtifactInSomeService, isLocalizedArtifactInService } = require('./odata/utils');
20
- const ReferenceFlattener = require('./odata/referenceFlattener');
21
- const { flattenCSN } = require('./odata/structureFlattener');
22
- const generateForeignKeys = require('./odata/generateForeignKeyElements');
23
- const expandStructKeysInAssociations = require('./odata/expandStructKeysInAssociations');
24
20
  const expandToFinalBaseType = require('./odata/toFinalBaseType');
25
21
  const { timetrace } = require('../utils/timetrace');
26
- const { attachPath } = require('./odata/attachPath');
27
22
  const enrichUniversalCsn = require('./universalCsn/universalCsnEnricher');
23
+ const flattening = require('./db/flattening');
24
+ const associations = require('./db/associations')
25
+ const expansion = require('./db/expansion');
28
26
  const generateDrafts = require('./draft/odata');
29
27
 
30
28
  const { addLocalizationViews } = require('./localized');
@@ -74,10 +72,10 @@ module.exports = { transform4odataWithCsn };
74
72
  function transform4odataWithCsn(inputModel, options) {
75
73
  timetrace.start('OData transformation');
76
74
  // copy the model as we don't want to change the input model
77
- let csn = cloneCsn(inputModel, options);
75
+ let csn = cloneCsnNonDict(inputModel, options);
78
76
 
79
- const { message, error, warning, info, throwWithError } = makeMessageFunction(csn, options, 'for.odata');
80
- throwWithError();
77
+ const { message, error, warning, info, throwWithAnyError } = makeMessageFunction(csn, options, 'for.odata');
78
+ throwWithAnyError();
81
79
 
82
80
  // the new transformer works only with new CSN
83
81
  checkCSNVersion(csn, options);
@@ -97,7 +95,6 @@ function transform4odataWithCsn(inputModel, options) {
97
95
  getServiceName,
98
96
  isAssocOrComposition,
99
97
  isAssociation,
100
- isStructured,
101
98
  inspectRef,
102
99
  artifactRef,
103
100
  effectiveType,
@@ -127,13 +124,13 @@ function transform4odataWithCsn(inputModel, options) {
127
124
 
128
125
  addLocalizationViews(csn, options, acceptLocalizedView);
129
126
 
130
- validate.forOdata(csn, {
127
+ const cleanup = validate.forOdata(csn, {
131
128
  message, error, warning, info, inspectRef, effectiveType, artifactRef, csn, options, csnUtils, services, getFinalBaseType, isAspect, isExternalServiceMember
132
129
  });
133
130
 
134
131
 
135
132
  // Throw exception in case of errors
136
- throwWithError();
133
+ throwWithAnyError();
137
134
 
138
135
  // Semantic checks before flattening regarding temporal data
139
136
  // TODO: Move in the validator
@@ -155,35 +152,38 @@ function transform4odataWithCsn(inputModel, options) {
155
152
  // Check if structured elements and managed associations are compared in an expression
156
153
  // and expand these structured elements. This tuple expansion allows all other
157
154
  // subsequent procession steps (especially a2j) to see plain paths in expressions.
158
- // If errors are detected, throwWithError() will return from further processing
155
+ // If errors are detected, throwWithAnyError() will return from further processing
159
156
  expandStructsInExpression(csn, { skipArtifact: isExternalServiceMember, drillRef: true });
160
157
 
161
- // handles reference flattening
162
- let referenceFlattener = new ReferenceFlattener();
163
- referenceFlattener.resolveAllReferences(csn, inspectRef, isStructured);
164
- attachPath(csn);
165
-
166
- referenceFlattener.applyAliasesInOnCond(csn, inspectRef);
167
-
168
158
  if (!structuredOData) {
169
- // flatten structures
170
- // @ts-ignore
171
- flattenCSN(csn, csnUtils, options, referenceFlattener, error, isExternalServiceMember);
172
- // flatten references
173
- referenceFlattener.flattenAllReferences(csn);
159
+ expansion.expandStructureReferences(csn, options, '_', { error, info, throwWithAnyError }, { skipArtifact: isExternalServiceMember });
160
+ const resolved = new WeakMap();
161
+ // No refs with struct-steps exist anymore
162
+ flattening.flattenAllStructStepsInRefs(csn, options, resolved, '_', { skipArtifact: isExternalServiceMember });
163
+ // No type references exist anymore
164
+ // Needs to happen exactly between flattenAllStructStepsInRefs and flattenElements to keep model resolvable.
165
+ // OData doesn't resolve type chains after the first 'items'
166
+ flattening.resolveTypeReferences(csn, options, resolved, '_',
167
+ { skip: [ 'action', 'aspect', 'event', 'function', 'type'], skipArtifact: isExternalServiceMember, skipStandard: { items: true } });
168
+ // No structured elements exists anymore
169
+ flattening.flattenElements(csn, options, '_', error,
170
+ { skip: ['action', 'aspect', 'event', 'function', 'type'], skipArtifact: isExternalServiceMember,
171
+ skipStandard: { items: true }, // don't drill further into .items
172
+ skipDict: { actions: true } }); // don't drill further into .actions -> bound actions, action-artifacts are handled by skip
174
173
  }
175
174
 
176
- // structure flattener reports errors, further processing is not safe -> throw exception in case of errors
177
- throwWithError();
175
+ // TODO: add the generated foreign keys to the columns when we are in a view
176
+ // see db/views.js::addForeignKeysToColumns
177
+ flattening.handleManagedAssociationsAndCreateForeignKeys(csn, options, error, '_', !structuredOData, { skipArtifact: isExternalServiceMember });
178
178
 
179
- // Process associations
180
- // 1. In case we generate flat mode, expand the structured foreign keys.
181
- // This logic rewrites the 'ref' for such keys with the corresponding flattened
182
- // elements.
183
- if (!structuredOData)
184
- expandStructKeysInAssociations(csn, referenceFlattener, csnUtils, isExternalServiceMember);
185
- // 2. generate foreign keys for managed associations
186
- generateForeignKeys(csn, options, referenceFlattener, csnUtils, error, isExternalServiceMember);
179
+ // Allow using managed associations as steps in on-conditions to access their fks
180
+ // To be done after handleManagedAssociationsAndCreateForeignKeys,
181
+ // since then the foreign keys of the managed assocs are part of the elements
182
+ if(!structuredOData)
183
+ forEachDefinition(csn, associations.getManagedAssocStepsInOnConditionFinalizer(csn, '_'));
184
+
185
+ // structure flattener reports errors, further processing is not safe -> throw exception in case of errors
186
+ throwWithAnyError();
187
187
 
188
188
  // Apply default type facets as set by options
189
189
  // Flatten on-conditions in unmanaged associations
@@ -207,22 +207,23 @@ function transform4odataWithCsn(inputModel, options) {
207
207
  generateDrafts(csn, options, services)
208
208
 
209
209
  // Deal with all kind of annotations manipulations here
210
+ const skipPersNameKinds = {'service':1, 'context':1, 'namespace':1, 'annotation':1, 'action':1, 'function':1};
210
211
  forEachDefinition(csn, (def, defName) => {
211
212
  // Resolve annotation shorthands for entities, types, annotations, ...
212
213
  renameShorthandAnnotations(def);
213
214
 
214
215
  // Annotate artifacts with their DB names if requested.
215
216
  // Skip artifacts that have no DB equivalent anyway
216
- if (options.toOdata.names && !['service', 'context', 'namespace', 'annotation', 'action', 'function'].includes(def.kind))
217
+ if (options.toOdata.names && !(def.kind in skipPersNameKinds))
217
218
  def['@cds.persistence.name'] = getArtifactDatabaseNameOf(defName, options.toOdata.names, csn);
218
219
 
219
- forEachMemberRecursively(def, (member, memberName, propertyName, path) => {
220
+ forEachMemberRecursively(def, (member, memberName, propertyName) => {
220
221
  // Annotate elements, foreign keys, parameters, etc. with their DB names if requested
221
222
  // Only these are actually required and don't annotate virtual elements in entities or types
222
223
  // as they have no DB representation (although in views)
223
- if (options.toOdata.names && typeof member === 'object' && !['action', 'function'].includes(member.kind) && propertyName !== 'enum' && (!member.virtual || def.query)) {
224
+ if (options.toOdata.names && typeof member === 'object' && !(member.kind === 'action' || member.kind === 'function') && propertyName !== 'enum' && (!member.virtual || def.query)) {
224
225
  // If we have a 'preserved dotted name' (i.e. we are a result of flattening), use that for the @cds.persistence.name annotation
225
- member['@cds.persistence.name'] = getElementDatabaseNameOf(referenceFlattener.getElementNameWithDots(path) || memberName, options.toOdata.names);
226
+ member['@cds.persistence.name'] = getElementDatabaseNameOf(member._flatElementNameWithDots || memberName, options.toOdata.names);
226
227
  }
227
228
 
228
229
  // Mark fields with @odata.on.insert/update as @Core.Computed
@@ -252,9 +253,9 @@ function transform4odataWithCsn(inputModel, options) {
252
253
  }, { skipArtifact: isExternalServiceMember })
253
254
 
254
255
  // Throw exception in case of errors
255
- throwWithError();
256
-
257
- if (options.testMode) csn = cloneCsn(csn, options); // sort, keep hidden properties
256
+ throwWithAnyError();
257
+ cleanup();
258
+ if (options.testMode) csn = cloneCsnNonDict(csn, options); // sort, keep hidden properties
258
259
  timetrace.stop();
259
260
  return csn;
260
261
 
@@ -3,10 +3,10 @@
3
3
  const { makeMessageFunction } = require('../base/messages');
4
4
  const { setProp } = require('../base/model');
5
5
  const { hasErrors } = require('../base/messages');
6
- const { cloneCsnDictionary } = require('../model/csnUtils');
6
+ const { cloneCsnDictionary, applyDefinitionAnnotationsFromExtensions} = require('../model/csnUtils');
7
7
  const { cleanSymbols } = require('../base/cleanSymbols.js');
8
8
  const {
9
- cloneCsn,
9
+ cloneCsnNonDict,
10
10
  forEachDefinition,
11
11
  forEachGeneric,
12
12
  forAllQueries,
@@ -86,6 +86,12 @@ function _addLocalizationViews(csn, options, useJoins, acceptLocalizedView = nul
86
86
 
87
87
  forEachDefinition(csn, definition => cleanSymbols(definition, _hasLocalizedView, _isViewForEntity, _isViewForView, _targetFor));
88
88
 
89
+ // In case that the user tried to annotate `localized.*` artifacts, apply them.
90
+ applyDefinitionAnnotationsFromExtensions(csn, {
91
+ overwrite: true,
92
+ filter: (name) => name.startsWith('localized.')
93
+ });
94
+
89
95
  sortCsnDefinitionsForTests(csn, options);
90
96
  return csn;
91
97
 
@@ -141,9 +147,8 @@ function _addLocalizationViews(csn, options, useJoins, acceptLocalizedView = nul
141
147
  else
142
148
  view = createLocalizedViewForEntity(art, artName, textElements);
143
149
 
150
+ copyPersistenceAnnotations(view, art);
144
151
  csn.definitions[viewName] = view;
145
-
146
- copyPersistenceAnnotations(csn.definitions[viewName], art);
147
152
  }
148
153
 
149
154
  /**
@@ -245,9 +250,9 @@ function _addLocalizationViews(csn, options, useJoins, acceptLocalizedView = nul
245
250
  };
246
251
 
247
252
  if (view.query)
248
- convenienceView.query = cloneCsn(view.query, options);
253
+ convenienceView.query = cloneCsnNonDict(view.query, options);
249
254
  else if (view.projection)
250
- convenienceView.projection = cloneCsn(view.projection, options);
255
+ convenienceView.projection = cloneCsnNonDict(view.projection, options);
251
256
 
252
257
  convenienceView.elements = cloneCsnDictionary(view.elements, options);
253
258
  convenienceView[_isViewForView] = true;
@@ -549,7 +554,7 @@ function _addLocalizationViews(csn, options, useJoins, acceptLocalizedView = nul
549
554
  if (!obj || typeof obj !== 'object' || Array.isArray(obj))
550
555
  return;
551
556
 
552
- for (const prop of [ 'ref', 'target', 'on' ]) {
557
+ for (const prop of [ 'ref', 'target' ]) {
553
558
  const val = obj[prop];
554
559
  if (prop === 'ref') {
555
560
  rewriteRefToLocalized(obj);
@@ -2,7 +2,7 @@
2
2
 
3
3
  const {
4
4
  forEachDefinition, forEachMemberRecursively,
5
- isBuiltinType, cloneCsnDictionary, cloneCsn,
5
+ isBuiltinType, cloneCsnDictionary, cloneCsnNonDict,
6
6
  } = require('../../model/csnUtils');
7
7
  const { isArtifactInSomeService, isArtifactInService } = require('./utils');
8
8
 
@@ -97,7 +97,7 @@ function expandToFinalBaseType(csn, transformers, csnUtils, services, options, i
97
97
  // type T: S; --> Integer;
98
98
  // type S: X; --> Integer;
99
99
  // type X: Integer;
100
- //
100
+ //
101
101
  // type A: B; -> {...}
102
102
  // type B: C; -> { ... }
103
103
  // type C { .... };
@@ -120,7 +120,7 @@ function expandToFinalBaseType(csn, transformers, csnUtils, services, options, i
120
120
  // type T: S; --> Integer;
121
121
  // type S: X; --> Integer;
122
122
  // type X: Integer;
123
- //
123
+ //
124
124
  // type {
125
125
  // struct_elt: many A; ---> stays the same
126
126
  // scalar_elt: T; ---> Integer;
@@ -162,7 +162,7 @@ function expandToFinalBaseType(csn, transformers, csnUtils, services, options, i
162
162
  // do the clone only if really needed
163
163
  if((finalType.items && !node.items) ||
164
164
  (finalType.elements && !node.elements))
165
- clone = cloneCsn({ definitions: { 'TypeDef': finalType } }, options);
165
+ clone = cloneCsnNonDict({ definitions: { 'TypeDef': finalType } }, options);
166
166
  if (finalType.items) {
167
167
  delete node.type;
168
168
  if(!node.items)
@@ -193,4 +193,4 @@ function expandToFinalBaseType(csn, transformers, csnUtils, services, options, i
193
193
  }
194
194
  }
195
195
 
196
- module.exports = expandToFinalBaseType;
196
+ module.exports = expandToFinalBaseType;