@sap/cds-compiler 4.6.2 → 4.7.4
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 +37 -0
- package/bin/cds_update_identifiers.js +6 -2
- package/bin/cdsc.js +1 -1
- package/doc/CHANGELOG_ARCHIVE.md +9 -9
- package/doc/CHANGELOG_BETA.md +6 -0
- package/lib/api/main.js +56 -9
- package/lib/api/options.js +6 -3
- package/lib/api/validate.js +20 -29
- package/lib/base/message-registry.js +27 -3
- package/lib/base/messages.js +8 -3
- package/lib/base/model.js +2 -0
- package/lib/checks/dbFeatureFlags.js +28 -0
- package/lib/checks/elements.js +81 -13
- package/lib/checks/enricher.js +3 -2
- package/lib/checks/validator.js +38 -4
- package/lib/compiler/assert-consistency.js +4 -4
- package/lib/compiler/checks.js +5 -4
- package/lib/compiler/define.js +2 -2
- package/lib/compiler/generate.js +2 -1
- package/lib/compiler/propagator.js +3 -11
- package/lib/compiler/shared.js +2 -1
- package/lib/compiler/tweak-assocs.js +43 -24
- package/lib/edm/annotations/edmJson.js +3 -0
- package/lib/edm/annotations/genericTranslation.js +156 -106
- package/lib/edm/annotations/preprocessAnnotations.js +11 -14
- package/lib/edm/csn2edm.js +27 -24
- package/lib/edm/edm.js +8 -8
- package/lib/edm/edmPreprocessor.js +135 -37
- package/lib/edm/edmUtils.js +20 -7
- package/lib/gen/Dictionary.json +1 -0
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +9 -11
- package/lib/gen/languageParser.js +5942 -5446
- package/lib/json/to-csn.js +7 -114
- package/lib/language/genericAntlrParser.js +106 -48
- package/lib/model/cloneCsn.js +203 -0
- package/lib/model/csnRefs.js +11 -3
- package/lib/model/csnUtils.js +42 -85
- package/lib/optionProcessor.js +2 -2
- package/lib/render/manageConstraints.js +1 -1
- package/lib/render/toCdl.js +133 -88
- package/lib/render/toHdbcds.js +1 -5
- package/lib/render/toSql.js +7 -9
- package/lib/render/utils/common.js +9 -16
- package/lib/transform/addTenantFields.js +277 -102
- package/lib/transform/db/applyTransformations.js +14 -9
- package/lib/transform/db/backlinks.js +2 -1
- package/lib/transform/db/constraints.js +60 -82
- package/lib/transform/db/expansion.js +6 -6
- package/lib/transform/db/featureFlags.js +5 -0
- package/lib/transform/db/flattening.js +4 -4
- package/lib/transform/db/killAnnotations.js +1 -0
- package/lib/transform/db/rewriteCalculatedElements.js +2 -2
- package/lib/transform/db/transformExists.js +12 -0
- package/lib/transform/db/views.js +5 -2
- package/lib/transform/draft/odata.js +7 -6
- package/lib/transform/effective/associations.js +2 -1
- package/lib/transform/effective/main.js +3 -2
- package/lib/transform/effective/types.js +6 -3
- package/lib/transform/forOdata.js +39 -24
- package/lib/transform/forRelationalDB.js +34 -27
- package/lib/transform/localized.js +29 -9
- package/lib/transform/odata/flattening.js +419 -0
- package/lib/transform/odata/toFinalBaseType.js +95 -15
- package/lib/transform/odata/typesExposure.js +9 -7
- package/lib/transform/transformUtils.js +7 -6
- package/lib/transform/translateAssocsToJoins.js +3 -3
- package/lib/utils/objectUtils.js +14 -0
- package/package.json +1 -1
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const { isDeprecatedEnabled, isBetaEnabled } = require('../base/model');
|
|
4
4
|
const transformUtils = require('./transformUtils');
|
|
5
|
-
const {
|
|
6
|
-
forEachDefinition,
|
|
5
|
+
const { forEachDefinition,
|
|
7
6
|
forEachMemberRecursively,
|
|
8
7
|
applyTransformationsOnNonDictionary,
|
|
9
8
|
getArtifactDatabaseNameOf,
|
|
@@ -18,13 +17,15 @@ const { isArtifactInSomeService, isLocalizedArtifactInService } = require('./oda
|
|
|
18
17
|
const expandToFinalBaseType = require('./odata/toFinalBaseType');
|
|
19
18
|
const { timetrace } = require('../utils/timetrace');
|
|
20
19
|
const enrichUniversalCsn = require('./universalCsn/universalCsnEnricher');
|
|
21
|
-
const flattening = require('./
|
|
20
|
+
const flattening = require('./odata/flattening');
|
|
22
21
|
const associations = require('./db/associations')
|
|
23
22
|
const expansion = require('./db/expansion');
|
|
24
23
|
const generateDrafts = require('./draft/odata');
|
|
25
24
|
|
|
26
25
|
const { addTenantFields } = require('./addTenantFields');
|
|
27
26
|
const { addLocalizationViews } = require('./localized');
|
|
27
|
+
const { cloneFullCsn } = require('../model/cloneCsn');
|
|
28
|
+
const { csnRefs } = require('../model/csnRefs');
|
|
28
29
|
|
|
29
30
|
// Transformation for ODATA. Expects a CSN 'inputModel', processes it for ODATA.
|
|
30
31
|
// The result should be suitable for consumption by EDMX processors (annotations and metadata)
|
|
@@ -72,7 +73,7 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
|
|
|
72
73
|
timetrace.start('OData transformation');
|
|
73
74
|
|
|
74
75
|
// copy the model as we don't want to change the input model
|
|
75
|
-
let csn =
|
|
76
|
+
let csn = cloneFullCsn(inputModel, options);
|
|
76
77
|
messageFunctions.setModel(csn);
|
|
77
78
|
|
|
78
79
|
const { message, error, warning, info, throwWithAnyError } = messageFunctions;
|
|
@@ -118,7 +119,7 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
|
|
|
118
119
|
if (options.csnFlavor === 'universal' && isBetaEnabled(options, 'enableUniversalCsn'))
|
|
119
120
|
enrichUniversalCsn(csn, options);
|
|
120
121
|
|
|
121
|
-
if (options.
|
|
122
|
+
if (options.tenantDiscriminator)
|
|
122
123
|
addTenantFields(csn, options);
|
|
123
124
|
|
|
124
125
|
const keepLocalizedViews = isDeprecatedEnabled(options, '_createLocalizedViews');
|
|
@@ -133,6 +134,9 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
|
|
|
133
134
|
// replace all type refs to builtin types with direct type
|
|
134
135
|
transformUtils.rewriteBuiltinTypeRef(csn);
|
|
135
136
|
|
|
137
|
+
// Rewrite paths in annotations only if beta modes are set
|
|
138
|
+
|
|
139
|
+
options.enrichAnnotations = true;
|
|
136
140
|
const cleanup = validate.forOdata(csn, {
|
|
137
141
|
message, error, warning, info, inspectRef, effectiveType, getFinalTypeInfo, artifactRef,
|
|
138
142
|
options, csnUtils, services, isAspect, isExternalServiceMember, recurseElements,
|
|
@@ -165,11 +169,11 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
|
|
|
165
169
|
// If in the future 'other' APIs that might support type refs are imported, these refs must be
|
|
166
170
|
// resolved here, as this is the OData transformation and sets the foundation for subsequent EDM
|
|
167
171
|
// rendering which may has to publish external definitions
|
|
168
|
-
expandToFinalBaseType(csn, transformers, csnUtils, services, options);
|
|
172
|
+
expandToFinalBaseType(csn, transformers, csnUtils, services, options, error);
|
|
169
173
|
|
|
170
174
|
// - Generate artificial draft fields on a structured CSN if requested, flattening and struct
|
|
171
175
|
// expansion do their magic including foreign key generation and annotation propagation.
|
|
172
|
-
generateDrafts(csn, options, services);
|
|
176
|
+
generateDrafts(csn, options, services, messageFunctions);
|
|
173
177
|
|
|
174
178
|
// Check if structured elements and managed associations are compared in an expression
|
|
175
179
|
// and expand these structured elements. This tuple expansion allows all other
|
|
@@ -180,21 +184,30 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
|
|
|
180
184
|
if (!structuredOData) {
|
|
181
185
|
expansion.expandStructureReferences(csn, options, '_', { error, info, throwWithAnyError }, csnUtils, { skipArtifact: isExternalServiceMember });
|
|
182
186
|
const resolved = new WeakMap();
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
flattening.
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
flattening.
|
|
190
|
-
{ skip: [
|
|
191
|
-
skipArtifact: isExternalServiceMember, skipStandard: { items: true } });
|
|
192
|
-
// No structured elements exists anymore
|
|
193
|
-
flattening.flattenElements(csn, options, messageFunctions, '_',
|
|
194
|
-
{ skip: ['action', 'aspect', 'event', 'function', 'type'],
|
|
187
|
+
|
|
188
|
+
const { inspectRef, effectiveType } = csnRefs(csn);
|
|
189
|
+
const { adaptRefs, transformer: refFlattener } = flattening.getStructRefFlatteningTransformer(csn, inspectRef, effectiveType, options, resolved, '_');
|
|
190
|
+
|
|
191
|
+
flattening.allInOneFlattening(csn, refFlattener, adaptRefs, inspectRef, isExternalServiceMember, error, csnUtils, options);
|
|
192
|
+
|
|
193
|
+
flattening.flattenAllStructStepsInRefs(csn, refFlattener, adaptRefs,
|
|
194
|
+
{ //skip: ['action', 'aspect', 'event', 'function', 'type'],
|
|
195
195
|
skipArtifact: isExternalServiceMember,
|
|
196
|
-
|
|
197
|
-
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
// replace structured with flat dictionaries that contain
|
|
199
|
+
// rewritten path expressions
|
|
200
|
+
forEachDefinition(csn, (def) => {
|
|
201
|
+
['elements', 'params'].forEach(dictName => {
|
|
202
|
+
if(def[`$${dictName}`])
|
|
203
|
+
def[dictName] = def[`$${dictName}`];
|
|
204
|
+
})
|
|
205
|
+
if(def.$flatAnnotations) {
|
|
206
|
+
Object.entries(def.$flatAnnotations).forEach(([an, av]) => {
|
|
207
|
+
def[an] = av;
|
|
208
|
+
})
|
|
209
|
+
}
|
|
210
|
+
});
|
|
198
211
|
}
|
|
199
212
|
|
|
200
213
|
// TODO: add the generated foreign keys to the columns when we are in a view
|
|
@@ -249,7 +262,7 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
|
|
|
249
262
|
!(propertyName === 'enum' || propertyName === 'returns') &&
|
|
250
263
|
(!member.virtual || def.query)) {
|
|
251
264
|
// If we have a 'preserved dotted name' (i.e. we are a result of flattening), use that for the @cds.persistence.name annotation
|
|
252
|
-
member['@cds.persistence.name'] = getElementDatabaseNameOf(member.
|
|
265
|
+
member['@cds.persistence.name'] = getElementDatabaseNameOf(member.$defPath?.slice(1).join('.') || memberName, options.sqlMapping, 'hana'); // hana to allow "hdbcds"
|
|
253
266
|
}
|
|
254
267
|
|
|
255
268
|
// Mark fields with @odata.on.insert/update as @Core.Computed
|
|
@@ -282,13 +295,15 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
|
|
|
282
295
|
forEachGeneric(csn, 'vocabularies', renameShorthandAnnotations);
|
|
283
296
|
}
|
|
284
297
|
|
|
298
|
+
cleanup();
|
|
285
299
|
// Throw exception in case of errors
|
|
286
300
|
throwWithAnyError();
|
|
287
|
-
cleanup();
|
|
288
|
-
if (options.testMode) csn = cloneCsnNonDict(csn, options); // sort, keep hidden properties
|
|
289
301
|
timetrace.stop('OData transformation');
|
|
290
302
|
return csn;
|
|
291
303
|
|
|
304
|
+
//--------------------------------------------------------------------
|
|
305
|
+
// HELPER SECTION STARTS HERE
|
|
306
|
+
|
|
292
307
|
// Mark elements that are annotated with @odata.on.insert/update with the annotation @Core.Computed.
|
|
293
308
|
function annotateCoreComputed(node) {
|
|
294
309
|
// If @Core.Computed is explicitly set, don't overwrite it!
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const { setProp, isBetaEnabled } = require('../base/model');
|
|
4
|
-
const {
|
|
5
|
-
forEachMemberRecursively, forAllQueries, applyTransformationsOnNonDictionary,
|
|
4
|
+
const { forEachMemberRecursively, forAllQueries, applyTransformationsOnNonDictionary,
|
|
6
5
|
getArtifactDatabaseNameOf, getElementDatabaseNameOf, isBuiltinType, applyTransformations,
|
|
7
6
|
isAspect, walkCsnPath, isPersistedOnDatabase
|
|
8
7
|
} = require('../model/csnUtils');
|
|
@@ -32,6 +31,8 @@ const temporal = require('./db/temporal');
|
|
|
32
31
|
const associations = require('./db/associations');
|
|
33
32
|
const backlinks = require('./db/backlinks');
|
|
34
33
|
const { getDefaultTypeLengths } = require('../render/utils/common');
|
|
34
|
+
const { featureFlags } = require('./db/featureFlags');
|
|
35
|
+
const { cloneCsnNonDict, cloneFullCsn } = require('../model/cloneCsn');
|
|
35
36
|
|
|
36
37
|
// By default: Do not process non-entities/views
|
|
37
38
|
function forEachDefinition(csn, cb) {
|
|
@@ -108,10 +109,10 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
|
|
|
108
109
|
|
|
109
110
|
timetrace.start('Clone CSN');
|
|
110
111
|
/** @type {CSN.Model} */
|
|
111
|
-
csn =
|
|
112
|
+
csn = cloneFullCsn(csn, options);
|
|
112
113
|
timetrace.stop('Clone CSN');
|
|
113
114
|
|
|
114
|
-
if (options.
|
|
115
|
+
if (options.tenantDiscriminator)
|
|
115
116
|
addTenantFields(csn, options);
|
|
116
117
|
|
|
117
118
|
checkCSNVersion(csn, options);
|
|
@@ -161,7 +162,8 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
|
|
|
161
162
|
// exit if validators found errors
|
|
162
163
|
throwWithAnyError();
|
|
163
164
|
|
|
164
|
-
|
|
165
|
+
if(csn.meta?.[featureFlags]?.$calculatedElements)
|
|
166
|
+
rewriteCalculatedElementsInViews(csn, options, csnUtils, pathDelimiter, messageFunctions);
|
|
165
167
|
|
|
166
168
|
// Needs to happen before tuple expansion, so the newly generated WHERE-conditions have it applied
|
|
167
169
|
handleExists(csn, options, error, csnUtils.inspectRef, csnUtils.initDefinition, csnUtils.dropDefinitionCache);
|
|
@@ -197,7 +199,6 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
|
|
|
197
199
|
|
|
198
200
|
bindCsnReferenceOnly();
|
|
199
201
|
|
|
200
|
-
|
|
201
202
|
// TODO: Instead of 3 separate applyTransformations, we could have each of them just return the "listeners", merge them into
|
|
202
203
|
// one big listener that then gets passed into one single applyTransformations. Each listener would then have to return an array of callbacks to call.
|
|
203
204
|
// With that, we could still ensure the processing order (assuming we don't run into problems with scoping).
|
|
@@ -395,18 +396,20 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
|
|
|
395
396
|
delete parent[prop];
|
|
396
397
|
}
|
|
397
398
|
|
|
399
|
+
function killParent(parent, a, b, path){
|
|
400
|
+
if(path.length > 2) {
|
|
401
|
+
const tail = path[path.length-1];
|
|
402
|
+
const parentPath = path.slice(0, -1)
|
|
403
|
+
const parentParent = walkCsnPath(csn, parentPath);
|
|
404
|
+
delete parentParent[tail];
|
|
405
|
+
} else {
|
|
406
|
+
delete parent.$ignore;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
398
410
|
const killers = {
|
|
399
411
|
// Used to ignore actions etc from processing and remove associations/elements
|
|
400
|
-
'$ignore':
|
|
401
|
-
if(path.length > 2) {
|
|
402
|
-
const tail = path[path.length-1];
|
|
403
|
-
const parentPath = path.slice(0, -1)
|
|
404
|
-
const parentParent = walkCsnPath(csn, parentPath);
|
|
405
|
-
delete parentParent[tail];
|
|
406
|
-
} else {
|
|
407
|
-
delete parent.$ignore;
|
|
408
|
-
}
|
|
409
|
-
},
|
|
412
|
+
'$ignore': killParent,
|
|
410
413
|
// Still used in flattenStructuredElements - in db/flattening.js
|
|
411
414
|
'_flatElementNameWithDots': killProp,
|
|
412
415
|
// Set when setting default string/binary length - used in copyTypeProperties and fixBorkedElementsOfLocalized
|
|
@@ -442,13 +445,16 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
|
|
|
442
445
|
}
|
|
443
446
|
}
|
|
444
447
|
|
|
445
|
-
|
|
448
|
+
if(options.sqlDialect === 'hana' && options.withHanaAssociations === false && doA2J) {
|
|
449
|
+
killers.target = killParent;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
applyTransformations(csn, killers, [], { skipIgnore: false });
|
|
446
453
|
|
|
447
454
|
redoProjections.forEach(fn => fn());
|
|
448
455
|
|
|
449
456
|
timetrace.stop('Transform CSN');
|
|
450
457
|
timetrace.stop('HANA transformation');
|
|
451
|
-
|
|
452
458
|
return csn;
|
|
453
459
|
|
|
454
460
|
/* ----------------------------------- Functions start here -----------------------------------------------*/
|
|
@@ -548,15 +554,16 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
|
|
|
548
554
|
// First pass: Set alias name for SELECTs without table alias. Required for setting proper table aliases
|
|
549
555
|
// for HDBCDS in naming mode HDBCDS. We use the same schema as the core-compiler, so duplicates should
|
|
550
556
|
// have already been reported.
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
++selectDepth;
|
|
559
|
-
|
|
557
|
+
if(options.transformation === 'hdbcds' && options.sqlMapping === 'hdbcds') {
|
|
558
|
+
let selectDepth = 0;
|
|
559
|
+
traverseQuery(artifact.query, null, null, (query, fromSelect) => {
|
|
560
|
+
if (!query.ref && !query.as && fromSelect) {
|
|
561
|
+
// Use +1; for UNION, it's the next select, for SELECT, it's increased later.
|
|
562
|
+
query.as = `$_select_${selectDepth + 1}__`;
|
|
563
|
+
}
|
|
564
|
+
if (query.SELECT) ++selectDepth;
|
|
565
|
+
});
|
|
566
|
+
}
|
|
560
567
|
|
|
561
568
|
const process = (parent, prop, query, path) => {
|
|
562
569
|
transformEntityOrViewPass2(parent, artifact, artifactName, path.concat(prop))
|
|
@@ -5,15 +5,18 @@ const { setProp, isDeprecatedEnabled} = require('../base/model');
|
|
|
5
5
|
const { forEachKey } = require('../utils/objectUtils');
|
|
6
6
|
const { cleanSymbols } = require('../base/cleanSymbols.js');
|
|
7
7
|
const {
|
|
8
|
-
cloneCsnDictionary,
|
|
9
|
-
cloneCsnNonDict,
|
|
10
8
|
applyAnnotationsFromExtensions,
|
|
11
9
|
forEachDefinition,
|
|
12
10
|
forEachGeneric,
|
|
13
11
|
forAllQueries,
|
|
14
|
-
sortCsnDefinitionsForTests,
|
|
15
12
|
} = require('../model/csnUtils');
|
|
16
|
-
const {CompilerAssertion} = require('../base/error');
|
|
13
|
+
const { CompilerAssertion } = require('../base/error');
|
|
14
|
+
const {
|
|
15
|
+
cloneCsnDict,
|
|
16
|
+
cloneCsnNonDict,
|
|
17
|
+
sortCsnDefinitionsForTests,
|
|
18
|
+
sortCsn
|
|
19
|
+
} = require('../model/cloneCsn');
|
|
17
20
|
|
|
18
21
|
/**
|
|
19
22
|
* Indicator that a definition is localized and has a convenience view.
|
|
@@ -104,7 +107,7 @@ const annoPersistenceSkip = '@cds.persistence.skip';
|
|
|
104
107
|
* If true, do not emit a warning for annotations on unknown `localized.*` views.
|
|
105
108
|
*/
|
|
106
109
|
function _addLocalizationViews(csn, options, config) {
|
|
107
|
-
const messageFunctions = makeMessageFunction(csn, options);
|
|
110
|
+
const messageFunctions = makeMessageFunction(csn, options, 'localized');
|
|
108
111
|
if (checkExistingLocalizationViews(csn, options, messageFunctions))
|
|
109
112
|
return csn;
|
|
110
113
|
|
|
@@ -117,7 +120,7 @@ function _addLocalizationViews(csn, options, config) {
|
|
|
117
120
|
createTransitiveConvenienceViews(); // 2 + 3
|
|
118
121
|
cleanDefinitionSymbols();
|
|
119
122
|
applyAnnotationsForLocalizedViews();
|
|
120
|
-
|
|
123
|
+
sortLocalizedForTests(csn, options);
|
|
121
124
|
messageFunctions.throwWithError();
|
|
122
125
|
return csn;
|
|
123
126
|
|
|
@@ -201,7 +204,7 @@ function _addLocalizationViews(csn, options, config) {
|
|
|
201
204
|
columns,
|
|
202
205
|
},
|
|
203
206
|
},
|
|
204
|
-
elements:
|
|
207
|
+
elements: cloneCsnDict(entity.elements, options),
|
|
205
208
|
[_isViewForEntity]: true,
|
|
206
209
|
};
|
|
207
210
|
copyLocation(convenienceView, entity);
|
|
@@ -280,7 +283,7 @@ function _addLocalizationViews(csn, options, config) {
|
|
|
280
283
|
else if (view.projection)
|
|
281
284
|
convenienceView.projection = cloneCsnNonDict(view.projection, options);
|
|
282
285
|
|
|
283
|
-
convenienceView.elements =
|
|
286
|
+
convenienceView.elements = cloneCsnDict(view.elements, options);
|
|
284
287
|
convenienceView[_isViewForView] = true;
|
|
285
288
|
copyLocation(convenienceView, view);
|
|
286
289
|
|
|
@@ -289,7 +292,7 @@ function _addLocalizationViews(csn, options, config) {
|
|
|
289
292
|
});
|
|
290
293
|
|
|
291
294
|
if (view.params)
|
|
292
|
-
convenienceView.params =
|
|
295
|
+
convenienceView.params = cloneCsnDict(view.params, options);
|
|
293
296
|
|
|
294
297
|
return convenienceView;
|
|
295
298
|
}
|
|
@@ -842,6 +845,23 @@ function hasLocalizedConvenienceView(csn, artifactName) {
|
|
|
842
845
|
return !isInLocalizedNamespace(artifactName) && !!csn.definitions[`localized.${ artifactName }`];
|
|
843
846
|
}
|
|
844
847
|
|
|
848
|
+
/**
|
|
849
|
+
* For tests (testMode), sort the generated localized definitions, i.e. their props,
|
|
850
|
+
* but also sort 'csn.definitions' if requested.
|
|
851
|
+
*
|
|
852
|
+
* @param {CSN.Model} csn
|
|
853
|
+
* @param {CSN.Options} options
|
|
854
|
+
*/
|
|
855
|
+
function sortLocalizedForTests(csn, options) {
|
|
856
|
+
if (options.testMode) {
|
|
857
|
+
for (const defName in csn.definitions) {
|
|
858
|
+
if (defName.startsWith('localized.'))
|
|
859
|
+
csn.definitions[defName] = sortCsn(csn.definitions[defName], options);
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
sortCsnDefinitionsForTests(csn, options);
|
|
863
|
+
}
|
|
864
|
+
|
|
845
865
|
module.exports = {
|
|
846
866
|
addLocalizationViews,
|
|
847
867
|
addLocalizationViewsWithJoins,
|